From fefc306a546c0a2216aa9dc9c45f61efd0305e09 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 16 Sep 2009 01:39:44 +0000 Subject: [PATCH 001/232] - Make PClass derive from DObject so that it can participate in garbage collection. - Import VM. SVN r1841 (scripting) --- src/d_dehacked.cpp | 12 +- src/dobjgc.cpp | 9 + src/dobjtype.cpp | 20 +- src/dobjtype.h | 29 +- src/v_video.h | 2 +- zdoom.vcproj | 28 + zscript/vm.h | 791 ++++++++++++++++++++++ zscript/vmdisasm.cpp | 343 ++++++++++ zscript/vmexec.cpp | 185 ++++++ zscript/vmexec.h | 1495 ++++++++++++++++++++++++++++++++++++++++++ zscript/vmframe.cpp | 294 +++++++++ zscript/vmops.h | 210 ++++++ 12 files changed, 3399 insertions(+), 19 deletions(-) create mode 100644 zscript/vm.h create mode 100644 zscript/vmdisasm.cpp create mode 100644 zscript/vmexec.cpp create mode 100644 zscript/vmexec.h create mode 100644 zscript/vmframe.cpp create mode 100644 zscript/vmops.h diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index f63978190..1ac3ff287 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -149,10 +149,10 @@ static TArray<const PClass *> WeaponNames; // List of states that are hacked to use a codepointer struct MBFParamState { - FState * state; + FState *state; int pointer; }; -static TArray<MBFParamState *> MBFParamStates; +static TArray<MBFParamState> MBFParamStates; // Data on how to correctly modify the codepointers struct CodePointerAlias { @@ -1610,9 +1610,9 @@ static void SetPointer(FState *state, PSymbol *sym, int frame = 0) { if (!symname.CompareNoCase(MBFCodePointers[i].name)) { - MBFParamState * newstate = new MBFParamState; - newstate->state = state; - newstate->pointer = i; + MBFParamState newstate; + newstate.state = state; + newstate.pointer = i; MBFParamStates.Push(newstate); break; // No need to cycle through the rest of the list. } @@ -2494,7 +2494,7 @@ static void UnloadDehSupp () // Handle MBF params here, before the required arrays are cleared for (unsigned int i=0; i < MBFParamStates.Size(); i++) { - SetDehParams(MBFParamStates[i]->state, MBFParamStates[i]->pointer); + SetDehParams(MBFParamStates[i].state, MBFParamStates[i].pointer); } MBFParamStates.Clear(); MBFParamStates.ShrinkToFit(); diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index 1c8e618bd..0ba5d7c81 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -327,6 +327,15 @@ static void MarkRoot() SectorMarker->SecNum = 0; } Mark(SectorMarker); + // Mark symbol tables + for (unsigned j = 0; j < PClass::m_Types.Size(); ++j) + { + PClass *cls = PClass::m_Types[j]; + if (cls != NULL) + { + cls->Symbols.MarkSymbols(); + } + } // Mark bot stuff. Mark(bglobal.firstthing); Mark(bglobal.body1); diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 03eecc7a9..93586bcbf 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -467,21 +467,37 @@ const PClass *PClass::NativeClass() const // Symbol tables ------------------------------------------------------------ +IMPLEMENT_ABSTRACT_CLASS(PSymbol); +IMPLEMENT_CLASS(PSymbolConst); +IMPLEMENT_CLASS(PSymbolVariable); +IMPLEMENT_CLASS(PSymbolActionFunction); + PSymbol::~PSymbol() { } +PSymbolTable::PSymbolTable() +: ParentSymbolTable(NULL) +{ +} + PSymbolTable::~PSymbolTable () { ReleaseSymbols(); } -void PSymbolTable::ReleaseSymbols() +void PSymbolTable::MarkSymbols() { for (unsigned int i = 0; i < Symbols.Size(); ++i) { - delete Symbols[i]; + GC::Mark(Symbols[i]); } +} + +void PSymbolTable::ReleaseSymbols() +{ + // The GC will take care of deleting the symbols. We just need to + // clear our references to them. Symbols.Clear(); } diff --git a/src/dobjtype.h b/src/dobjtype.h index 88defaefe..d58ce2f00 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -16,8 +16,10 @@ enum ESymbolType SYM_ActionFunction }; -struct PSymbol +class PSymbol : public DObject { + DECLARE_ABSTRACT_CLASS(PSymbol, DObject); +public: virtual ~PSymbol(); ESymbolType SymbolType; @@ -29,8 +31,10 @@ protected: // A constant value --------------------------------------------------------- -struct PSymbolConst : public PSymbol +class PSymbolConst : public PSymbol { + DECLARE_CLASS(PSymbolConst, PSymbol); +public: int ValueType; union { @@ -39,17 +43,21 @@ struct PSymbolConst : public PSymbol }; PSymbolConst(FName name) : PSymbol(name, SYM_Const) {} + PSymbolConst() : PSymbol(NAME_None, SYM_Const) {} }; // A variable --------------------------------------------------------- -struct PSymbolVariable : public PSymbol +class PSymbolVariable : public PSymbol { + DECLARE_CLASS(PSymbolVariable, PSymbol); +public: FExpressionType ValueType; int size; intptr_t offset; PSymbolVariable(FName name) : PSymbol(name, SYM_Variable) {} + PSymbolVariable() : PSymbol(NAME_None, SYM_Variable) {} }; // An action function ------------------------------------------------------- @@ -74,26 +82,27 @@ struct FState; struct StateCallData; typedef void (*actionf_p)(AActor *self, AActor *stateowner, FState *state, int parameters, StateCallData *statecall); -struct PSymbolActionFunction : public PSymbol +class PSymbolActionFunction : public PSymbol { + DECLARE_CLASS(PSymbolActionFunction, PSymbol); +public: FString Arguments; actionf_p Function; int defaultparameterindex; PSymbolActionFunction(FName name) : PSymbol(name, SYM_ActionFunction) {} + PSymbolActionFunction() : PSymbol(NAME_None, SYM_ActionFunction) {} }; // A symbol table ----------------------------------------------------------- -class PSymbolTable +struct PSymbolTable { -public: - PSymbolTable() : ParentSymbolTable(NULL) - { - } - + PSymbolTable(); ~PSymbolTable(); + void MarkSymbols(); + // Sets the table to use for searches if this one doesn't contain the // requested symbol. void SetParentTable (PSymbolTable *parent); diff --git a/src/v_video.h b/src/v_video.h index c6857d55a..84a59db50 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -382,7 +382,7 @@ protected: DFrameBuffer () {} private: - DWORD LastMS, LastSec, FrameCount, LastCount, LastTic; + uint32 LastMS, LastSec, FrameCount, LastCount, LastTic; }; diff --git a/zdoom.vcproj b/zdoom.vcproj index 2b0c1b899..a416fa6a8 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -6446,6 +6446,34 @@ > </File> </Filter> + <Filter + Name="ZScript" + > + <File + RelativePath=".\zscript\vm.h" + > + </File> + <File + RelativePath=".\zscript\vmdisasm.cpp" + > + </File> + <File + RelativePath=".\zscript\vmexec.cpp" + > + </File> + <File + RelativePath=".\zscript\vmexec.h" + > + </File> + <File + RelativePath=".\zscript\vmframe.cpp" + > + </File> + <File + RelativePath=".\zscript\vmops.h" + > + </File> + </Filter> </Files> <Globals> </Globals> diff --git a/zscript/vm.h b/zscript/vm.h new file mode 100644 index 000000000..8a8b9e9f8 --- /dev/null +++ b/zscript/vm.h @@ -0,0 +1,791 @@ +#ifndef VM_H +#define VM_H + +#include "zstring.h" +#include "dobject.h" + +#define MAX_RETURNS 8 // Maximum number of results a function called by script code can return +#define MAX_TRY_DEPTH 8 // Maximum number of nested TRYs in a single function + + +typedef unsigned char VM_UBYTE; +typedef signed char VM_SBYTE; +typedef unsigned short VM_UHALF; +typedef signed short VM_SHALF; +typedef unsigned int VM_UWORD; +typedef signed int VM_SWORD; + +#define VM_EPSILON (1/1024.0) + +enum +{ +#include "vmops.h" +NUM_OPS +}; + +// Flags for A field of CMPS +enum +{ + CMP_CHECK = 1, + + CMP_EQ = 0, + CMP_LT = 2, + CMP_LE = 4, + CMP_METHOD_MASK = 6, + + CMP_BK = 8, + CMP_CK = 16, + CMP_APPROX = 32, +}; + +// Floating point operations for FLOP +enum +{ + FLOP_ABS, + FLOP_NEG, + FLOP_ACOS, + FLOP_ASIN, + FLOP_ATAN, + FLOP_COS, + FLOP_COSH, + FLOP_EXP, + FLOP_LOG, + FLOP_LOG10, + FLOP_SIN, + FLOP_SINH, + FLOP_TAN, + FLOP_TANH, + FLOP_SQRT, + FLOP_CEIL, + FLOP_FLOOR, +}; + +// Cast operations +enum +{ + CAST_I2F, + CAST_I2S, + CAST_F2I, + CAST_F2S, + CAST_P2S, + CAST_S2I, + CAST_S2F, +}; + +// Register types for VMParam +enum +{ + REGT_INT = 0, + REGT_FLOAT = 1, + REGT_STRING = 2, + REGT_POINTER = 3, + REGT_TYPE = 3, + + REGT_KONST = 4, + REGT_MULTIREG = 8, // (e.g. a vector) + REGT_FINAL = 16, // used with RET: this is the final return value + REGT_ADDROF = 32, // used with PARAM: pass address of this register + + REGT_NIL = 255 // parameter was omitted +}; + +// Tags for address registers +enum +{ + ATAG_GENERIC, // pointer to something; we don't care what + ATAG_OBJECT, // pointer to an object; will be followed by GC + + // The following are all for documentation during debugging and are + // functionally no different than ATAG_GENERIC. + + ATAG_FRAMEPOINTER, // pointer to extra stack frame space for this function + ATAG_DREGISTER, // pointer to a data register + ATAG_FREGISTER, // pointer to a float register + ATAG_SREGISTER, // pointer to a string register + ATAG_AREGISTER, // pointer to an address register + +}; + +class VMFunction : public DObject +{ + DECLARE_CLASS(VMFunction, DObject); +public: + bool Native; +}; + +enum EVMOpMode +{ + MODE_ASHIFT = 0, + MODE_BSHIFT = 4, + MODE_CSHIFT = 8, + MODE_BCSHIFT = 12, + + MODE_ATYPE = 15 << MODE_ASHIFT, + MODE_BTYPE = 15 << MODE_BSHIFT, + MODE_CTYPE = 15 << MODE_CSHIFT, + MODE_BCTYPE = 31 << MODE_BCSHIFT, + + MODE_I = 0, + MODE_F, + MODE_S, + MODE_P, + MODE_V, + MODE_X, + MODE_KI, + MODE_KF, + MODE_KS, + MODE_KP, + MODE_KV, + MODE_UNUSED, + MODE_IMMS, + MODE_IMMZ, + MODE_JOINT, + + MODE_PARAM, + MODE_THROW, + MODE_CATCH, + MODE_CAST, + + MODE_AI = MODE_I << MODE_ASHIFT, + MODE_AF = MODE_F << MODE_ASHIFT, + MODE_AS = MODE_S << MODE_ASHIFT, + MODE_AP = MODE_P << MODE_ASHIFT, + MODE_AV = MODE_V << MODE_ASHIFT, + MODE_AX = MODE_X << MODE_ASHIFT, + MODE_AKP = MODE_KP << MODE_ASHIFT, + MODE_AUNUSED = MODE_UNUSED << MODE_ASHIFT, + MODE_AIMMS = MODE_IMMS << MODE_ASHIFT, + MODE_AIMMZ = MODE_IMMZ << MODE_ASHIFT, + + MODE_BI = MODE_I << MODE_BSHIFT, + MODE_BF = MODE_F << MODE_BSHIFT, + MODE_BS = MODE_S << MODE_BSHIFT, + MODE_BP = MODE_P << MODE_BSHIFT, + MODE_BV = MODE_V << MODE_BSHIFT, + MODE_BX = MODE_X << MODE_BSHIFT, + MODE_BKI = MODE_KI << MODE_BSHIFT, + MODE_BKF = MODE_KF << MODE_BSHIFT, + MODE_BKS = MODE_KS << MODE_BSHIFT, + MODE_BKP = MODE_KP << MODE_BSHIFT, + MODE_BKV = MODE_KV << MODE_BSHIFT, + MODE_BUNUSED = MODE_UNUSED << MODE_BSHIFT, + MODE_BIMMS = MODE_IMMS << MODE_BSHIFT, + MODE_BIMMZ = MODE_IMMZ << MODE_BSHIFT, + + MODE_CI = MODE_I << MODE_CSHIFT, + MODE_CF = MODE_F << MODE_CSHIFT, + MODE_CS = MODE_S << MODE_CSHIFT, + MODE_CP = MODE_P << MODE_CSHIFT, + MODE_CV = MODE_V << MODE_CSHIFT, + MODE_CX = MODE_X << MODE_CSHIFT, + MODE_CKI = MODE_KI << MODE_CSHIFT, + MODE_CKF = MODE_KF << MODE_CSHIFT, + MODE_CKS = MODE_KS << MODE_CSHIFT, + MODE_CKP = MODE_KP << MODE_CSHIFT, + MODE_CKV = MODE_KV << MODE_CSHIFT, + MODE_CUNUSED = MODE_UNUSED << MODE_CSHIFT, + MODE_CIMMS = MODE_IMMS << MODE_CSHIFT, + MODE_CIMMZ = MODE_IMMZ << MODE_CSHIFT, + + MODE_BCJOINT = (MODE_JOINT << MODE_BSHIFT) | (MODE_JOINT << MODE_CSHIFT), + MODE_BCKI = MODE_KI << MODE_BCSHIFT, + MODE_BCKF = MODE_KF << MODE_BCSHIFT, + MODE_BCKS = MODE_KS << MODE_BCSHIFT, + MODE_BCKP = MODE_KP << MODE_BCSHIFT, + MODE_BCIMMS = MODE_IMMS << MODE_BCSHIFT, + MODE_BCIMMZ = MODE_IMMZ << MODE_BCSHIFT, + MODE_BCPARAM = MODE_PARAM << MODE_BCSHIFT, + MODE_BCTHROW = MODE_THROW << MODE_BCSHIFT, + MODE_BCCATCH = MODE_CATCH << MODE_BCSHIFT, + MODE_BCCAST = MODE_CAST << MODE_BCSHIFT, + + MODE_ABCJOINT = (MODE_JOINT << MODE_ASHIFT) | MODE_BCJOINT, +}; + +struct VMOpInfo +{ + const char *Name; + int Mode; +}; + +extern const VMOpInfo OpInfo[NUM_OPS]; + +struct VMReturn +{ + void *Location; + VM_SHALF RegNum; // Used to find ObjFlag index for pointers; set negative if the caller is native code and doesn't care + VM_UBYTE RegType; // Same as VMParam RegType, except REGT_KONST is invalid; only used by asserts + + void SetInt(int val) + { + *(int *)Location = val; + } + void SetFloat(double val) + { + *(double *)Location = val; + } + void SetVector(const double val[3]) + { + ((double *)Location)[0] = val[0]; + ((double *)Location)[1] = val[1]; + ((double *)Location)[2] = val[2]; + } + void SetString(const FString &val) + { + *(FString *)Location = val; + } + void SetPointer(void *val) + { + *(void **)Location = val; + } + + void IntAt(int *loc) + { + Location = loc; + RegNum = -1; + RegType = REGT_INT; + } + void FloatAt(double *loc) + { + Location = loc; + RegNum = -1; + RegType = REGT_FLOAT; + } + void StringAt(FString *loc) + { + Location = loc; + RegNum = -1; + RegType = REGT_STRING; + } + void PointerAt(void **loc) + { + Location = loc; + RegNum = -1; + RegType = REGT_POINTER; + } +}; + +struct VMRegisters; + + +struct VMValue +{ + union + { + int i; + struct { void *a; int atag; }; + double f; + struct { int pad[3]; int Type; }; + struct { int foo[4]; } biggest; + }; + + // Unfortunately, FString cannot be used directly. + // Fortunately, it is relatively simple. + FString &s() { return *(FString *)&a; } + const FString &s() const { return *(FString *)&a; } + + VMValue() + { + a = NULL; + Type = REGT_NIL; + } + ~VMValue() + { + Kill(); + } + VMValue(const VMValue &o) + { + biggest = o.biggest; + if (Type == REGT_STRING) + { + ::new(&s()) FString(o.s()); + } + } + VMValue(int v) + { + i = v; + Type = REGT_INT; + } + VMValue(double v) + { + f = v; + Type = REGT_FLOAT; + } + VMValue(const char *s) + { + ::new(&a) FString(s); + Type = REGT_STRING; + } + VMValue(const FString &s) + { + ::new(&a) FString(s); + Type = REGT_STRING; + } + VMValue(DObject *v) + { + a = v; + atag = ATAG_OBJECT; + Type = REGT_POINTER; + } + VMValue(void *v) + { + a = v; + atag = ATAG_GENERIC; + Type = REGT_POINTER; + } + VMValue(void *v, int tag) + { + a = v; + atag = tag; + Type = REGT_POINTER; + } + VMValue &operator=(const VMValue &o) + { + if (o.Type == REGT_STRING) + { + if (Type == REGT_STRING) + { + s() = o.s(); + } + else + { + new(&s()) FString(o.s()); + Type = REGT_STRING; + } + } + else + { + Kill(); + biggest = o.biggest; + } + return *this; + } + VMValue &operator=(int v) + { + Kill(); + i = v; + Type = REGT_INT; + return *this; + } + VMValue &operator=(double v) + { + Kill(); + f = v; + Type = REGT_FLOAT; + return *this; + } + VMValue &operator=(const FString &v) + { + if (Type == REGT_STRING) + { + s() = v; + } + else + { + ::new(&s()) FString(v); + Type = REGT_STRING; + } + return *this; + } + VMValue &operator=(const char *v) + { + if (Type == REGT_STRING) + { + s() = v; + } + else + { + ::new(&s()) FString(v); + Type = REGT_STRING; + } + return *this; + } + VMValue &operator=(DObject *v) + { + Kill(); + a = v; + atag = ATAG_OBJECT; + Type = REGT_POINTER; + return *this; + } + VMValue &operator=(void *v) + { + Kill(); + a = v; + atag = ATAG_GENERIC; + Type = REGT_POINTER; + return *this; + } + void SetNil() + { + Kill(); + Type = REGT_NIL; + } + bool operator==(const VMValue &o) + { + return Test(o) == 0; + } + bool operator!=(const VMValue &o) + { + return Test(o) != 0; + } + bool operator< (const VMValue &o) + { + return Test(o) < 0; + } + bool operator<=(const VMValue &o) + { + return Test(o) <= 0; + } + bool operator> (const VMValue &o) + { + return Test(o) > 0; + } + bool operator>=(const VMValue &o) + { + return Test(o) >= 0; + } + int Test(const VMValue &o, int inexact=false) + { + double diff; + + if (Type == o.Type) + { + switch(Type) + { + case REGT_NIL: + return 0; + + case REGT_INT: + return i - o.i; + + case REGT_FLOAT: + diff = f - o.f; +do_double: if (inexact) + { + return diff < -VM_EPSILON ? -1 : diff > VM_EPSILON ? 1 : 0; + } + return diff < 0 ? -1 : diff > 0 ? 1 : 0; + + case REGT_STRING: + return inexact ? s().CompareNoCase(o.s()) : s().Compare(o.s()); + + case REGT_POINTER: + return int((const VM_UBYTE *)a - (const VM_UBYTE *)o.a); + } + assert(0); // Should not get here + return 2; + } + if (Type == REGT_FLOAT && o.Type == REGT_INT) + { + diff = f - o.i; + goto do_double; + } + if (Type == REGT_INT && o.Type == REGT_FLOAT) + { + diff = i - o.f; + goto do_double; + } + // Bad comparison + return 2; + } + FString ToString() + { + if (Type == REGT_STRING) + { + return s(); + } + else if (Type == REGT_NIL) + { + return "nil"; + } + FString t; + if (Type == REGT_INT) + { + t.Format ("%d", i); + } + else if (Type == REGT_FLOAT) + { + t.Format ("%.14g", f); + } + else if (Type == REGT_POINTER) + { + // FIXME + t.Format ("Object: %p", a); + } + return t; + } + int ToInt() + { + if (Type == REGT_INT) + { + return i; + } + if (Type == REGT_FLOAT) + { + return int(f); + } + if (Type == REGT_STRING) + { + return s().ToLong(); + } + // FIXME + return 0; + } + double ToDouble() + { + if (Type == REGT_FLOAT) + { + return f; + } + if (Type == REGT_INT) + { + return i; + } + if (Type == REGT_STRING) + { + return s().ToDouble(); + } + // FIXME + return 0; + } + void Kill() + { + if (Type == REGT_STRING) + { + s().~FString(); + } + } +}; + +// VM frame layout: +// VMFrame header +// parameter stack - 16 byte boundary, 16 bytes each +// double registers - 8 bytes each +// string registers - 4 or 8 bytes each +// address registers - 4 or 8 bytes each +// data registers - 4 bytes each +// address register tags-1 byte each +// extra space - 16 byte boundary +struct VMFrame +{ + VMFrame *ParentFrame; + VMFunction *Func; + VM_UBYTE NumRegD; + VM_UBYTE NumRegF; + VM_UBYTE NumRegS; + VM_UBYTE NumRegA; + VM_UHALF MaxParam; + VM_UHALF NumParam; // current number of parameters + + static int FrameSize(int numregd, int numregf, int numregs, int numrega, int numparam, int numextra) + { + int size = (sizeof(VMFrame) + 15) & ~15; + size += numparam * sizeof(VMValue); + size += numregf * sizeof(double); + size += numrega * (sizeof(void *) + sizeof(VM_UBYTE)); + size += numregs * sizeof(FString); + size += numregd * sizeof(int); + if (numextra != 0) + { + size = (size + 15) & ~15; + size += numextra; + } + return size; + } + + int *GetRegD() const + { + return (int *)(GetRegA() + NumRegA); + } + + double *GetRegF() const + { + return (double *)(GetParam() + MaxParam); + } + + FString *GetRegS() const + { + return (FString *)(GetRegF() + NumRegF); + } + + void **GetRegA() const + { + return (void **)(GetRegS() + NumRegS); + } + + VM_UBYTE *GetRegATag() const + { + return (VM_UBYTE *)(GetRegD() + NumRegD); + } + + VMValue *GetParam() const + { + return (VMValue *)(((size_t)(this + 1) + 15) & ~15); + } + + void *GetExtra() const + { + VM_UBYTE *ptag = GetRegATag(); + ptrdiff_t ofs = ptag - (VM_UBYTE *)this; + return (VM_UBYTE *)this + ((ofs + NumRegA + 15) & ~15); + } + + void GetAllRegs(int *&d, double *&f, FString *&s, void **&a, VM_UBYTE *&atag, VMValue *¶m) const + { + // Calling the individual functions produces suboptimal code. :( + param = GetParam(); + f = (double *)(param + MaxParam); + s = (FString *)(f + NumRegF); + a = (void **)(s + NumRegS); + d = (int *)(a + NumRegA); + atag = (VM_UBYTE *)(d + NumRegD); + } + + void InitRegS(); +}; + +struct VMRegisters +{ + VMRegisters(const VMFrame *frame) + { + frame->GetAllRegs(d, f, s, a, atag, param); + } + + VMRegisters(const VMRegisters &o) + : d(o.d), f(o.f), s(o.s), a(o.a), atag(o.atag), param(o.param) + { } + + int *d; + double *f; + FString *s; + void **a; + VM_UBYTE *atag; + VMValue *param; +}; + +struct VMException : public DObject +{ + DECLARE_CLASS(VMFunction, DObject); +}; + +class VMScriptFunction : public VMFunction +{ + DECLARE_CLASS(VMScriptFunction, VMFunction); +public: + const VM_UBYTE *Code; + int *KonstD; + double *KonstF; + FString *KonstS; + void **KonstA; + int ExtraSpace; + int NumCodeBytes; + VM_UBYTE NumRegD; + VM_UBYTE NumRegF; + VM_UBYTE NumRegS; + VM_UBYTE NumRegA; + VM_UBYTE NumKonstD; + VM_UBYTE NumKonstF; + VM_UBYTE NumKonstS; + VM_UBYTE NumKonstA; + VM_UHALF MaxParam; // Maximum number of parameters this function has on the stack at once + VM_UBYTE NumArgs; // Number of arguments this function takes +}; + +class VMFrameStack +{ +public: + VMFrameStack(); + ~VMFrameStack(); + VMFrame *AllocFrame(int numregd, int numregf, int numregs, int numrega); + VMFrame *AllocFrame(VMScriptFunction *func); + VMFrame *PopFrame(); + VMFrame *TopFrame() + { + assert(Blocks != NULL && Blocks->LastFrame != NULL); + return Blocks->LastFrame; + } + int Call(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults, VMException **trap=NULL); +private: + enum { BLOCK_SIZE = 4096 }; // Default block size + struct BlockHeader + { + BlockHeader *NextBlock; + VMFrame *LastFrame; + VM_UBYTE *FreeSpace; + int BlockSize; + }; + BlockHeader *Blocks; + BlockHeader *UnusedBlocks; + VMFrame *Alloc(int size); +}; + +class VMNativeFunction : public VMFunction +{ + DECLARE_CLASS(VMNativeFunction, VMFunction); +public: + // Return value is the number of results. + int (*NativeCall)(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret); +}; + + +class VMParamFiller +{ +public: + VMParamFiller(const VMFrame *frame) : Reg(frame), RegD(0), RegF(0), RegS(0), RegA(0) {} + VMParamFiller(const VMRegisters *reg) : Reg(*reg), RegD(0), RegF(0), RegS(0), RegA(0) {} + + void ParamInt(int val) + { + Reg.d[RegD++] = val; + } + + void ParamFloat(double val) + { + Reg.f[RegF++] = val; + } + + void ParamString(FString &val) + { + Reg.s[RegS++] = val; + } + + void ParamString(const char *val) + { + Reg.s[RegS++] = val; + } + + void ParamObject(DObject *obj) + { + Reg.a[RegA] = obj; + Reg.atag[RegA] = true; + RegA++; + } + + void ParamPointer(void *ptr) + { + Reg.a[RegA] = ptr; + Reg.atag[RegA] = false; + RegA++; + } + +private: + const VMRegisters Reg; + int RegD, RegF, RegS, RegA; +}; + + +enum EVMEngine +{ + VMEngine_Default, + VMEngine_Unchecked, + VMEngine_Checked +}; + +void VMSelectEngine(EVMEngine engine); +extern int (*VMExec)(VMFrameStack *stack, const VM_UBYTE *pc, VMReturn *ret, int numret); +void VMFillParams(VMValue *params, VMFrame *callee, int numparam); + +void VMDisasm(const VM_UBYTE *code, int codesize, const VMScriptFunction *func); + +#endif diff --git a/zscript/vmdisasm.cpp b/zscript/vmdisasm.cpp new file mode 100644 index 000000000..7ca2a3dc3 --- /dev/null +++ b/zscript/vmdisasm.cpp @@ -0,0 +1,343 @@ +#include "vm.h" + +#define LI MODE_AI | MODE_BCJOINT | MODE_BCIMMS +#define LKI MODE_AI | MODE_BCJOINT | MODE_BCKI +#define LKF MODE_AF | MODE_BCJOINT | MODE_BCKF +#define LKS MODE_AS | MODE_BCJOINT | MODE_BCKS +#define LKP MODE_AP | MODE_BCJOINT | MODE_BCKP +#define LFP MODE_AP | MODE_BUNUSED | MODE_CUNUSED + +#define RIRPKI MODE_AI | MODE_BP | MODE_CKI +#define RIRPRI MODE_AI | MODE_BP | MODE_CI +#define RFRPKI MODE_AF | MODE_BP | MODE_CKI +#define RFRPRI MODE_AF | MODE_BP | MODE_CI +#define RSRPKI MODE_AS | MODE_BP | MODE_CKI +#define RSRPRI MODE_AS | MODE_BP | MODE_CI +#define RPRPKI MODE_AP | MODE_BP | MODE_CKI +#define RPRPRI MODE_AP | MODE_BP | MODE_CI +#define RVRPKI MODE_AV | MODE_BP | MODE_CKI +#define RVRPRI MODE_AV | MODE_BP | MODE_CI +#define RIRPI8 MODE_AI | MODE_BP | MODE_CIMMZ + +#define RPRIKI MODE_AP | MODE_BI | MODE_CKI +#define RPRIRI MODE_AP | MODE_BI | MODE_CI +#define RPRFKI MODE_AP | MODE_BF | MODE_CKI +#define RPRFRI MODE_AP | MODE_BF | MODE_CI +#define RPRSKI MODE_AP | MODE_BS | MODE_CKI +#define RPRSRI MODE_AP | MODE_BS | MODE_CI +#define RPRPKI MODE_AP | MODE_BP | MODE_CKI +#define RPRPRI MODE_AP | MODE_BP | MODE_CI +#define RPRVKI MODE_AP | MODE_BV | MODE_CKI +#define RPRVRI MODE_AP | MODE_BV | MODE_CI +#define RPRII8 MODE_AP | MODE_BI | MODE_CIMMZ + +#define RIRI MODE_AI | MODE_BI | MODE_CUNUSED +#define RFRF MODE_AF | MODE_BF | MODE_CUNUSED +#define RSRS MODE_AS | MODE_BS | MODE_CUNUSED +#define RPRP MODE_AP | MODE_BP | MODE_CUNUSED +#define RXRXI8 MODE_AX | MODE_BX | MODE_CIMMZ +#define RPRPRP MODE_AP | MODE_BP | MODE_CP +#define RPRPKP MODE_AP | MODE_BP | MODE_CKP + +#define RII16 MODE_AI | MODE_BCJOINT | MODE_BCIMMS +#define I24 MODE_ABCJOINT +#define I8 MODE_AIMMZ | MODE_BUNUSED | MODE_CUNUSED +#define __BCP MODE_AUNUSED | MODE_BCJOINT | MODE_BCPARAM +#define RPI8I8 MODE_AP | MODE_BIMMZ | MODE_CIMMZ +#define KPI8I8 MODE_AKP | MODE_BIMMZ | MODE_CIMMZ +#define I8BCP MODE_AIMMZ | MODE_BCJOINT | MODE_BCPARAM +#define THROW MODE_AIMMZ | MODE_BCTHROW +#define CATCH MODE_AIMMZ | MODE_BCCATCH +#define CAST MODE_AX | MODE_BX | MODE_CIMMZ | MODE_BCCAST + +#define RSRSRS MODE_AS | MODE_BS | MODE_CS +#define RIRS MODE_AI | MODE_BS | MODE_CUNUSED +#define I8RXRX MODE_AIMMZ | MODE_BX | MODE_CX + +#define RIRIRI MODE_AI | MODE_BI | MODE_CI +#define RIRII8 MODE_AI | MODE_BI | MODE_CIMMZ +#define RIRIKI MODE_AI | MODE_BI | MODE_CKI +#define RIKIRI MODE_AI | MODE_BKI | MODE_CI +#define RIKII8 MODE_AI | MODE_BKI | MODE_CIMMZ +#define RIRIIs MODE_AI | MODE_BI | MODE_CIMMS +#define RIRI MODE_AI | MODE_BI | MODE_CUNUSED +#define I8RIRI MODE_AIMMZ | MODE_BI | MODE_CI +#define I8RIKI MODE_AIMMZ | MODE_BI | MODE_CKI +#define I8KIRI MODE_AIMMZ | MODE_BKI | MODE_CI + +#define RFRFRF MODE_AF | MODE_BF | MODE_CF +#define RFRFKF MODE_AF | MODE_BF | MODE_CKF +#define RFKFRF MODE_AF | MODE_BKF | MODE_CF +#define I8RFRF MODE_AIMMZ | MODE_BF | MODE_CF +#define I8RFKF MODE_AIMMZ | MODE_BF | MODE_CKF +#define I8KFRF MODE_AIMMZ | MODE_BKF | MODE_CF +#define RFRFI8 MODE_AF | MODE_BF | MODE_CIMMZ + +#define RVRV MODE_AV | MODE_BV | MODE_CUNUSED +#define RVRVRV MODE_AV | MODE_BV | MODE_CV +#define RVRVKV MODE_AV | MODE_BV | MODE_CKV +#define RVKVRV MODE_AV | MODE_BKV | MODE_CV +#define RFRV MODE_AF | MODE_BV | MODE_CUNUSED +#define I8RVRV MODE_AIMMZ | MODE_BV | MODE_CV +#define I8RVKV MODE_AIMMZ | MODE_BV | MODE_CKV + +#define RPRPRI MODE_AP | MODE_BP | MODE_CI +#define RPRPKI MODE_AP | MODE_BP | MODE_CKI +#define RIRPRP MODE_AI | MODE_BP | MODE_CP +#define I8RPRP MODE_AIMMZ | MODE_BP | MODE_CP +#define I8RPKP MODE_AIMMZ | MODE_BP | MODE_CKP + +const VMOpInfo OpInfo[NUM_OPS] = +{ +#define xx(op, name, mode) { #name, mode } +#include "vmops.h" +}; + +#ifdef WORDS_BIGENDIAN +#define JMPOFS(x) ((*(VM_SWORD *)(x) << 8) >> 6) +#else +#define JMPOFS(x) ((*(VM_SWORD *)(x) >> 6) & ~3) +#endif + +static int print_reg(int col, int arg, int mode, int immshift, const VMScriptFunction *func); + +void VMDisasm(const VM_UBYTE *code, int codesize, const VMScriptFunction *func) +{ + const char *name; + int col; + int mode; + int a; + + for (int i = 0; i < codesize; i += 4) + { + name = OpInfo[code[i]].Name; + mode = OpInfo[code[i]].Mode; + a = code[i+1]; + + // String comparison encodes everything in a single instruction. + if (code[i] == OP_CMPS) + { + switch (a & CMP_METHOD_MASK) + { + case CMP_EQ: name = "eq"; break; + case CMP_LT: name = "lt"; break; + case CMP_LE: name = "le"; break; + } + mode = MODE_AIMMZ; + mode |= (a & CMP_BK) ? MODE_BKS : MODE_BS; + mode |= (a & CMP_CK) ? MODE_CKS : MODE_CS; + a &= CMP_CHECK | CMP_APPROX; + } + + printf("%08x: %02x%02x%02x%02x %-8s", i, code[i], code[i+1], code[i+2], code[i+3], name); + col = 0; + switch (code[i]) + { + case OP_JMP: + case OP_TRY: + col = printf("%08x", i + 4 + JMPOFS(&code[i])); + break; + + case OP_RET: + if (code[i+2] != REGT_NIL) + { + if ((code[i+2] & REGT_FINAL) && a == 0) + { + col = print_reg(0, *(VM_UHALF *)&code[i+2], MODE_PARAM, 16, func); + } + else + { + col = print_reg(0, a, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func); + col += print_reg(col, *(VM_UHALF *)&code[i+2], MODE_PARAM, 16, func); + if (code[i+2] & REGT_FINAL) + { + col += printf(" [final]"); + } + } + } + break; + + default: + if ((mode & MODE_BCTYPE) == MODE_BCCAST) + { + switch (code[i+3]) + { + case CAST_I2F: + mode = MODE_AF | MODE_BI | MODE_CUNUSED; + break; + case CAST_I2S: + mode = MODE_AS | MODE_BI | MODE_CUNUSED; + break; + case CAST_F2I: + mode = MODE_AI | MODE_BF | MODE_CUNUSED; + break; + case CAST_F2S: + mode = MODE_AS | MODE_BF | MODE_CUNUSED; + break; + case CAST_P2S: + mode = MODE_AS | MODE_BP | MODE_CUNUSED; + break; + case CAST_S2I: + mode = MODE_AI | MODE_BS | MODE_CUNUSED; + break; + case CAST_S2F: + mode = MODE_AF | MODE_BS | MODE_CUNUSED; + break; + default: + mode = MODE_AX | MODE_BX | MODE_CIMMZ; + break; + } + } + col = print_reg(0, a, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func); + if ((mode & MODE_BCTYPE) == MODE_BCTHROW) + { + mode = (code[i+1] == 0) ? (MODE_BP | MODE_CUNUSED) : (MODE_BKP | MODE_CUNUSED); + } + else if ((mode & MODE_BCTYPE) == MODE_BCCATCH) + { + switch (code[i+1]) + { + case 0: + mode = MODE_BUNUSED | MODE_CUNUSED; + break; + case 1: + mode = MODE_BUNUSED | MODE_CP; + break; + case 2: + mode = MODE_BP | MODE_CP; + break; + case 3: + mode = MODE_BKP | MODE_CP; + break; + default: + mode = MODE_BIMMZ | MODE_CIMMZ; + break; + } + } + if ((mode & (MODE_BTYPE | MODE_CTYPE)) == MODE_BCJOINT) + { + col += print_reg(col, *(VM_UHALF *)&code[i+2], (mode & MODE_BCTYPE) >> MODE_BCSHIFT, 16, func); + } + else + { + col += print_reg(col, code[i+2], (mode & MODE_BTYPE) >> MODE_BSHIFT, 24, func); + col += print_reg(col, code[i+3], (mode & MODE_CTYPE) >> MODE_CSHIFT, 24, func); + } + break; + } + if (col > 30) + { + col = 30; + } + printf("%*c", 30 - col, ';'); + if (code[i] == OP_JMP || code[i] == OP_TRY) + { + printf("%d\n", JMPOFS(&code[i]) >> 2); + } + else + { + printf("%d,%d,%d\n", code[i+1], code[i+2], code[i+3]); + } + } +} + +static int print_reg(int col, int arg, int mode, int immshift, const VMScriptFunction *func) +{ + if (mode == MODE_UNUSED) + { + return 0; + } + if (col > 0) + { + col = printf(","); + } + switch(mode) + { + case MODE_I: + return col+printf("d%d", arg); + case MODE_F: + return col+printf("f%d", arg); + case MODE_S: + return col+printf("s%d", arg); + case MODE_P: + return col+printf("a%d", arg); + case MODE_V: + return col+printf("v%d", arg); + + case MODE_KI: + if (func != NULL) + { + return col+printf("%d", func->KonstD[arg]); + } + return printf("kd%d", arg); + case MODE_KF: + if (func != NULL) + { + return col+printf("%f", func->KonstF[arg]); + } + return col+printf("kf%d", arg); + case MODE_KS: + if (func != NULL) + { + return col+printf("\"%s\"", func->KonstS[arg].GetChars()); + } + return col+printf("ks%d", arg); + case MODE_KP: + if (func != NULL) + { + return col+printf("%p", func->KonstA[arg]); + } + return col+printf("ka%d", arg); + case MODE_KV: + if (func != NULL) + { + return col+printf("(%f,%f,%f)", func->KonstF[arg], func->KonstF[arg+1], func->KonstF[arg+2]); + } + return col+printf("kv%d", arg); + + case MODE_IMMS: + return col+printf("%d", (arg << immshift) >> immshift); + + case MODE_IMMZ: + return col+printf("%d", arg); + + case MODE_PARAM: + { + union { VM_UHALF Together; struct { VM_UBYTE RegType, RegNum; }; } p; + p.Together = arg; + switch (p.RegType & (REGT_TYPE | REGT_KONST | REGT_MULTIREG)) + { + case REGT_INT: + return col+printf("d%d", p.RegNum); + case REGT_FLOAT: + return col+printf("f%d", p.RegNum); + case REGT_STRING: + return col+printf("s%d", p.RegNum); + case REGT_POINTER: + return col+printf("a%d", p.RegNum); + case REGT_FLOAT | REGT_MULTIREG: + return col+printf("v%d", p.RegNum); + case REGT_INT | REGT_KONST: + return col+print_reg(0, p.RegNum, MODE_KI, 0, func); + case REGT_FLOAT | REGT_KONST: + return col+print_reg(0, p.RegNum, MODE_KF, 0, func); + case REGT_STRING | REGT_KONST: + return col+print_reg(0, p.RegNum, MODE_KS, 0, func); + case REGT_POINTER | REGT_KONST: + return col+print_reg(0, p.RegNum, MODE_KP, 0, func); + case REGT_FLOAT | REGT_MULTIREG | REGT_KONST: + return col+print_reg(0, p.RegNum, MODE_KV, 0, func); + default: + return col+printf("param[t=%d,%c,%c,n=%d]", + p.RegType & REGT_TYPE, + p.RegType & REGT_KONST ? 'k' : 'r', + p.RegType & REGT_MULTIREG ? 'm' : 's', + p.RegNum); + } + } + + default: + return col+printf("$%d", arg); + } + return col; +} diff --git a/zscript/vmexec.cpp b/zscript/vmexec.cpp new file mode 100644 index 000000000..9c32b4fc5 --- /dev/null +++ b/zscript/vmexec.cpp @@ -0,0 +1,185 @@ +#include <math.h> +#include "vm.h" + +#define IMPLEMENT_VMEXEC + +#if !defined(COMPGOTO) && defined(__GNUC__) +#define COMPGOTO 1 +#endif + +#if COMPGOTO +#define OP(x) x +#define NEXTOP do { unsigned op = *pc; a = pc[1]; pc += 4; goto *ops[op]; } while(0) +#else +#define OP(x) case OP_##x +#define NEXTOP break +#endif + +#define luai_nummod(a,b) ((a) - floor((a)/(b))*(b)) + +#define A (*(pc - 3)) +#define B (*(pc - 2)) +#define C ( *(pc - 1)) +#define Cs (*(VM_SBYTE *)(pc - 1)) +#define BC (*(VM_UHALF *)(pc - 2)) +#define BCs (*(VM_SHALF *)(pc - 2)) + +#ifdef WORDS_BIGENDIAN +#define JMPOFS(x) ((*(VM_SWORD *)(x) << 8) >> 6) +#else +#define JMPOFS(x) ((*(VM_SWORD *)(x) >> 6) & ~3) +#endif + +#define KC (konst[C]) +#define RC (reg.i[C]) + +#define PA (reg.a[A]) +#define PB (reg.a[B]) + +#define ASSERTD(x) assert((unsigned)(x) < f->NumRegD) +#define ASSERTF(x) assert((unsigned)(x) < f->NumRegF) +#define ASSERTA(x) assert((unsigned)(x) < f->NumRegA) +#define ASSERTS(x) assert((unsigned)(x) < f->NumRegS) + +#define ASSERTKD(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstD) +#define ASSERTKF(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstF) +#define ASSERTKA(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstA) +#define ASSERTKS(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstS) + +#define THROW(x) + +#define CMPJMP(test) \ + if ((test) == (a & CMP_CHECK)) { \ + assert(*pc == OP_JMP); \ + pc += 4 + JMPOFS(pc); \ + } else { \ + pc += 4; \ + } + +enum +{ + X_READ_NIL, + X_WRITE_NIL, + X_TOO_MANY_TRIES, +}; + +#define GETADDR(a,o,x) \ + if (a == 0) { THROW(x); } \ + ptr = (VM_SBYTE *)a + x \ + +static const VM_UWORD ZapTable[16] = +{ + 0x00000000, 0x000000FF, 0x0000FF00, 0x0000FFFF, + 0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x00FFFFFF, + 0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF, + 0xFFFF0000, 0xFFFF00FF, 0xFFFFFF00, 0xFFFFFFFF +}; + +#ifdef NDEBUG +#define WAS_NDEBUG 1 +#else +#define WAS_NDEBUG 0 +#endif + +#if WAS_NDEBUG +#undef NDEBUG +#endif +#undef assert +#include <assert.h> +struct VMExec_Checked +{ +#include "vmexec.h" +}; +#if WAS_NDEBUG +#define NDEBUG +#endif + +#if !WAS_NDEBUG +#define NDEBUG +#endif +#undef assert +#include <assert.h> +struct VMExec_Unchecked +{ +#include "vmexec.h" +}; +#if !WAS_NDEBUG +#undef NDEBUG +#endif +#undef assert +#include <assert.h> + +int (*VMExec)(VMFrameStack *stack, const VM_UBYTE *pc, VMReturn *ret, int numret) = +#ifdef NDEBUG +VMExec_Unchecked::Exec +#else +VMExec_Checked::Exec +#endif +; + +void VMSelectEngine(EVMEngine engine) +{ + switch (engine) + { + case VMEngine_Default: +#ifdef NDEBUG + VMExec = VMExec_Unchecked::Exec; +#else + VMExec = VMExec_Checked::Exec; +#endif + break; + case VMEngine_Unchecked: + VMExec = VMExec_Unchecked::Exec; + break; + case VMEngine_Checked: + VMExec = VMExec_Checked::Exec; + break; + } +} + +//=========================================================================== +// +// VMFillParams +// +// Takes parameters from the paramater stack and stores them in the callee's +// registers. +// +//=========================================================================== + +void VMFillParams(VMValue *params, VMFrame *callee, int numparam) +{ + unsigned int regd, regf, regs, rega; + VMScriptFunction *calleefunc = static_cast<VMScriptFunction *>(callee->Func); + const VMRegisters calleereg(callee); + + assert(calleefunc != NULL && !calleefunc->Native); + assert(numparam == calleefunc->NumArgs); + assert(REGT_INT == 0 && REGT_FLOAT == 1 && REGT_STRING == 2 && REGT_POINTER == 3); + + regd = regf = regs = rega = 0; + for (int i = 0; i < numparam; ++i) + { + VMValue &p = params[i]; + if (p.Type < REGT_STRING) + { + if (p.Type == REGT_INT) + { + calleereg.d[regd++] = p.i; + } + else // p.Type == REGT_FLOAT + { + calleereg.f[regf++] = p.f; + } + } + else if (p.Type == REGT_STRING) + { + calleereg.s[regs++] = p.s(); + } + else + { + assert(p.Type == REGT_POINTER); + calleereg.a[rega] = p.a; + calleereg.atag[rega++] = p.atag; + } + } +} diff --git a/zscript/vmexec.h b/zscript/vmexec.h new file mode 100644 index 000000000..c0b268589 --- /dev/null +++ b/zscript/vmexec.h @@ -0,0 +1,1495 @@ +#ifndef IMPLEMENT_VMEXEC +#error vmexec.h must not be #included outside vmexec.cpp. Use vm.h instead. +#endif + + +static int Exec(VMFrameStack *stack, const VM_UBYTE *pc, VMReturn *ret, int numret) +{ +#if COMPGOTO + static const void * const ops[256] = + { +#define xx(op,sym,mode) &&op +#include "vmops.h" + }; +#endif + const VM_UBYTE *exception_frames[MAX_TRY_DEPTH]; + int try_depth = 0; + VMFrame *f = stack->TopFrame(); + VMScriptFunction *sfunc; + const VMRegisters reg(f); + const int *konstd; + const double *konstf; + const FString *konsts; + void * const *konsta; + + if (f->Func != NULL && !f->Func->Native) + { + sfunc = static_cast<VMScriptFunction *>(f->Func); + konstd = sfunc->KonstD; + konstf = sfunc->KonstF; + konsts = sfunc->KonstS; + konsta = sfunc->KonstA; + } + else + { + sfunc = NULL; + konstd = NULL; + konstf = NULL; + konsts = NULL; + konsta = NULL; + } + + void *ptr; + double fb, fc; + const double *fbp, *fcp; + int a, b, c; + +begin: + try + { +#if !COMPGOTO + VM_UBYTE op; + for(;;) switch(op = pc[0], a = pc[1], pc += 4, op) +#else + NEXTOP; +#endif + { + OP(LI): + ASSERTD(a); + reg.d[a] = BCs; + NEXTOP; + OP(LK): + ASSERTD(a); ASSERTKD(BC); + reg.d[a] = konstd[BC]; + NEXTOP; + OP(LKF): + ASSERTF(a); ASSERTKF(BC); + reg.f[a] = konstf[BC]; + NEXTOP; + OP(LKS): + ASSERTS(a); ASSERTKS(BC); + reg.s[a] = konsts[BC]; + NEXTOP; + OP(LKP): + ASSERTA(a); ASSERTKA(BC); + reg.a[a] = konsta[BC]; + reg.atag[a] = ATAG_OBJECT; + NEXTOP; + OP(LFP): + ASSERTA(a); assert(sfunc != NULL); assert(sfunc->ExtraSpace > 0); + reg.a[a] = f->GetExtra(); + reg.atag[a] = ATAG_FRAMEPOINTER; + NEXTOP; + + OP(LB): + ASSERTD(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.d[a] = *(VM_SBYTE *)ptr; + NEXTOP; + OP(LB_R): + ASSERTD(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.d[a] = *(VM_SBYTE *)ptr; + NEXTOP; + OP(LH): + ASSERTD(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.d[a] = *(VM_SHALF *)ptr; + NEXTOP; + OP(LH_R): + ASSERTD(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.d[a] = *(VM_SHALF *)ptr; + NEXTOP; + OP(LW): + ASSERTD(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.d[a] = *(VM_SWORD *)ptr; + NEXTOP; + OP(LW_R): + ASSERTD(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.d[a] = *(VM_SWORD *)ptr; + NEXTOP; + OP(LBU): + ASSERTD(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.d[a] = *(VM_UBYTE *)ptr; + NEXTOP; + OP(LBU_R): + ASSERTD(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.d[a] = *(VM_UBYTE *)ptr; + NEXTOP; + OP(LHU): + ASSERTD(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.d[a] = *(VM_UHALF *)ptr; + NEXTOP; + OP(LHU_R): + ASSERTD(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.d[a] = *(VM_UHALF *)ptr; + NEXTOP; + + OP(LSP): + ASSERTF(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.f[a] = *(float *)ptr; + NEXTOP; + OP(LSP_R): + ASSERTF(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.f[a] = *(float *)ptr; + NEXTOP; + OP(LDP): + ASSERTF(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.f[a] = *(double *)ptr; + NEXTOP; + OP(LDP_R): + ASSERTF(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.f[a] = *(double *)ptr; + NEXTOP; + + OP(LS): + ASSERTS(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.s[a] = *(FString *)ptr; + NEXTOP; + OP(LS_R): + ASSERTS(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.s[a] = *(FString *)ptr; + NEXTOP; + OP(LO): + ASSERTA(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.a[a] = *(void **)ptr; + reg.atag[a] = ATAG_OBJECT; + NEXTOP; + OP(LO_R): + ASSERTA(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.a[a] = *(void **)ptr; + reg.atag[a] = ATAG_OBJECT; + NEXTOP; + OP(LP): + ASSERTA(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.a[a] = *(void **)ptr; + reg.atag[a] = ATAG_GENERIC; + NEXTOP; + OP(LP_R): + ASSERTA(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.a[a] = *(void **)ptr; + reg.atag[a] = ATAG_GENERIC; + NEXTOP; + OP(LV): + ASSERTF(a+2); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + { + float *v = (float *)ptr; + reg.f[a] = v[0]; + reg.f[a+1] = v[1]; + reg.f[a+2] = v[2]; + } + NEXTOP; + OP(LV_R): + ASSERTF(a+2); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + { + float *v = (float *)ptr; + reg.f[a] = v[0]; + reg.f[a+1] = v[1]; + reg.f[a+2] = v[2]; + } + NEXTOP; + OP(LX): + ASSERTF(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.f[a] = *(VM_SWORD *)ptr / 65536.0; + NEXTOP; + OP(LX_R): + ASSERTF(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.f[a] = *(VM_SWORD *)ptr / 65536.0; + NEXTOP; + OP(LBIT): + ASSERTD(a); ASSERTA(B); + GETADDR(PB,0,X_READ_NIL); + reg.d[a] = !!(*(VM_UBYTE *)ptr & C); + NEXTOP; + + OP(SB): + ASSERTA(a); ASSERTD(B); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + *(VM_SBYTE *)ptr = reg.d[B]; + NEXTOP; + OP(SB_R): + ASSERTA(a); ASSERTD(B); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + *(VM_SBYTE *)ptr = reg.d[B]; + NEXTOP; + OP(SH): + ASSERTA(a); ASSERTD(B); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + *(VM_SHALF *)ptr = reg.d[B]; + NEXTOP; + OP(SH_R): + ASSERTA(a); ASSERTD(B); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + *(VM_SHALF *)ptr = reg.d[B]; + NEXTOP; + OP(SW): + ASSERTA(a); ASSERTD(B); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + *(VM_SWORD *)ptr = reg.d[B]; + NEXTOP; + OP(SW_R): + ASSERTA(a); ASSERTD(B); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + *(VM_SWORD *)ptr = reg.d[B]; + NEXTOP; + OP(SSP): + ASSERTA(a); ASSERTF(B); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + *(float *)ptr = (float)reg.f[B]; + NEXTOP; + OP(SSP_R): + ASSERTA(a); ASSERTF(B); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + *(float *)ptr = (float)reg.f[B]; + NEXTOP; + OP(SDP): + ASSERTA(a); ASSERTF(B); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + *(double *)ptr = reg.f[B]; + NEXTOP; + OP(SDP_R): + ASSERTA(a); ASSERTF(B); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + *(double *)ptr = reg.f[B]; + NEXTOP; + OP(SS): + ASSERTA(a); ASSERTS(B); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + *(FString *)ptr = reg.s[B]; + NEXTOP; + OP(SS_R): + ASSERTA(a); ASSERTS(B); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + *(FString *)ptr = reg.s[B]; + NEXTOP; + OP(SP): + ASSERTA(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + *(void **)ptr = reg.a[B]; + NEXTOP; + OP(SP_R): + ASSERTA(a); ASSERTA(B); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + *(void **)ptr = reg.a[B]; + NEXTOP; + OP(SV): + ASSERTA(a); ASSERTF(B+2); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + { + float *v = (float *)ptr; + v[0] = (float)reg.f[B]; + v[1] = (float)reg.f[B+1]; + v[2] = (float)reg.f[B+2]; + } + NEXTOP; + OP(SV_R): + ASSERTA(a); ASSERTF(B+2); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + { + float *v = (float *)ptr; + v[0] = (float)reg.f[B]; + v[1] = (float)reg.f[B+1]; + v[2] = (float)reg.f[B+2]; + } + NEXTOP; + OP(SX): + ASSERTA(a); ASSERTF(B); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + *(VM_SWORD *)ptr = (VM_SWORD)(reg.f[B] * 65536.0); + NEXTOP; + OP(SX_R): + ASSERTA(a); ASSERTF(B); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + *(VM_SWORD *)ptr = (VM_SWORD)(reg.f[B] * 65536.0); + NEXTOP; + OP(SBIT): + ASSERTA(a); ASSERTD(B); + GETADDR(PA,0,X_WRITE_NIL); + if (reg.d[B]) + { + *(VM_UBYTE *)ptr |= C; + } + else + { + *(VM_UBYTE *)ptr &= ~C; + } + NEXTOP; + + OP(MOVE): + ASSERTD(a); ASSERTD(B); + reg.d[a] = reg.d[B]; + NEXTOP; + OP(MOVEF): + ASSERTF(a); ASSERTF(B); + reg.f[a] = reg.f[B]; + NEXTOP; + OP(MOVES): + ASSERTS(a); ASSERTS(B); + reg.s[a] = reg.s[B]; + NEXTOP; + OP(MOVEA): + ASSERTA(a); ASSERTA(B); + reg.a[a] = reg.a[B]; + reg.atag[a] = reg.atag[B]; + NEXTOP; + OP(CAST): + if (C == CAST_I2F) + { + ASSERTF(a); ASSERTD(B); + reg.f[A] = reg.d[B]; + } + else if (C == CAST_F2I) + { + ASSERTD(a); ASSERTF(B); + reg.d[A] = (int)reg.f[B]; + } + else + { + DoCast(reg, f, a, B, C); + } + NEXTOP; + OP(DYNCAST_R): + // UNDONE + NEXTOP; + OP(DYNCAST_K): + // UNDONE + NEXTOP; + + OP(TEST): + ASSERTD(a); + if (reg.d[a] != BC) + { + pc += 4; + } + NEXTOP; + OP(JMP): + pc += JMPOFS(pc - 4); + NEXTOP; + OP(IJMP): + ASSERTD(a); + pc += (BCs + reg.d[a]) << 2; + assert(*pc == OP_JMP); + pc += (1 + *((VM_SHALF *)pc + 1)) << 2; + NEXTOP; + OP(PARAM): + assert(f->NumParam < sfunc->MaxParam); + { + VMValue *param = ®.param[f->NumParam++]; + b = B; + if (b == REGT_NIL) + { + ::new(param) VMValue(); + } + else + { + switch(b & (REGT_TYPE | REGT_KONST | REGT_ADDROF)) + { + case REGT_INT: + assert(C < f->NumRegD); + ::new(param) VMValue(reg.d[C]); + break; + case REGT_INT | REGT_ADDROF: + assert(C < f->NumRegD); + ::new(param) VMValue(®.d[C], ATAG_DREGISTER); + break; + case REGT_INT | REGT_KONST: + assert(C < sfunc->NumKonstD); + ::new(param) VMValue(konstd[C]); + break; + case REGT_STRING: + assert(C < f->NumRegS); + ::new(param) VMValue(reg.s[C]); + break; + case REGT_STRING | REGT_ADDROF: + assert(C < f->NumRegS); + ::new(param) VMValue(®.s[C], ATAG_SREGISTER); + break; + case REGT_STRING | REGT_KONST: + assert(C < sfunc->NumKonstS); + ::new(param) VMValue(konsts[C]); + break; + case REGT_POINTER: + assert(C < f->NumRegA); + ::new(param) VMValue(reg.a[C], reg.atag[C]); + break; + case REGT_POINTER | REGT_ADDROF: + assert(C < f->NumRegA); + ::new(param) VMValue(®.a[C], ATAG_AREGISTER); + break; + case REGT_POINTER | REGT_KONST: + assert(C < sfunc->NumKonstA); + ::new(param) VMValue(konsta[C]); + break; + case REGT_FLOAT: + if (b & REGT_MULTIREG) + { + assert(C < f->NumRegF - 2); + assert(f->NumParam < sfunc->MaxParam - 1); + ::new(param) VMValue(reg.f[C]); + ::new(param+1) VMValue(reg.f[C+1]); + ::new(param+2) VMValue(reg.f[C+2]); + f->NumParam += 2; + } + else + { + assert(C < f->NumRegF); + ::new(param) VMValue(reg.f[C]); + } + break; + case REGT_FLOAT | REGT_ADDROF: + assert(C < f->NumRegF); + ::new(param) VMValue(®.f[C], ATAG_FREGISTER); + break; + case REGT_FLOAT | REGT_KONST: + if (b & REGT_MULTIREG) + { + assert(C < sfunc->NumKonstF - 2); + assert(f->NumParam < sfunc->MaxParam - 1); + ::new(param) VMValue(konstf[C]); + ::new(param+1) VMValue(konstf[C+1]); + ::new(param+2) VMValue(konstf[C+2]); + f->NumParam += 2; + } + else + { + assert(C < sfunc->NumKonstF); + ::new(param) VMValue(konstf[C]); + } + break; + default: + assert(0); + break; + } + } + } + NEXTOP; + OP(CALL_K): + ASSERTKA(a); + ptr = sfunc->KonstA[a]; + goto Do_CALL; + OP(CALL): + ASSERTA(a); + ptr = reg.a[a]; + Do_CALL: + assert(B <= f->NumParam); + assert(C <= MAX_RETURNS); + { + VMFunction *call = (VMFunction *)ptr; + VMReturn returns[MAX_RETURNS]; + int numret; + + FillReturns(reg, f, returns, pc, C); + if (call->Native) + { + numret = static_cast<VMNativeFunction *>(call)->NativeCall(stack, reg.param + f->NumParam - B, B, returns, C); + } + else + { + VMScriptFunction *script = static_cast<VMScriptFunction *>(call); + VMFrame *newf = stack->AllocFrame(script); + VMFillParams(reg.param + f->NumParam - B, newf, B); + try + { + numret = Exec(stack, script->Code, returns, C); + } + catch(...) + { + stack->PopFrame(); + throw; + } + stack->PopFrame(); + } + assert(numret == C); + for (b = B; b != 0; --b) + { + reg.param[--f->NumParam].~VMValue(); + } + pc += C * 4; // Skip RESULTs + } + NEXTOP; + OP(RET): + if (B == REGT_NIL) + { // No return values + return 0; + } + assert(a < numret); + SetReturn(reg, f, &ret[a], B, C); + if (B & REGT_FINAL) + { + return a + 1; + } + NEXTOP; + OP(RESULT): + // This instruction is just a placeholder to indicate where a return + // value should be stored. It does nothing on its own and should not + // be executed. + assert(0); + NEXTOP; + + OP(TRY): + assert(try_depth < MAX_TRY_DEPTH); + if (try_depth >= MAX_TRY_DEPTH) + { + THROW(X_TOO_MANY_TRIES); + } + assert(*(pc + JMPOFS(pc - 4)) == OP_CATCH); + exception_frames[try_depth++] = pc + JMPOFS(pc - 4); + NEXTOP; + OP(UNTRY): + assert(a <= try_depth); + try_depth -= a; + NEXTOP; + OP(THROW): + if (a == 0) + { + ASSERTA(B); + throw((VMException *)reg.a[B]); + } + else + { + ASSERTKA(B); + throw((VMException *)konsta[B]); + } + NEXTOP; + OP(CATCH): + // This instruction is handled by our own catch handler and should + // not be executed by the normal VM code. + assert(0); + NEXTOP; + + OP(CONCAT): + ASSERTS(a); ASSERTS(B); ASSERTS(C); + { + FString *rB = ®.s[B]; + FString *rC = ®.s[C]; + FString concat(*rB); + for (++rB; rB <= rC; ++rB) + { + concat += *rB; + } + reg.s[a] = concat; + } + NEXTOP; + OP(LENS): + ASSERTD(a); ASSERTS(B); + reg.d[a] = (int)reg.s[B].Len(); + NEXTOP; + + OP(CMPS): + // String comparison is a fairly expensive operation, so I've + // chosen to conserve a few opcodes by condensing all the + // string comparisons into a single one. + { + const FString *b, *c; + int test, method; + bool cmp; + + if (a & CMP_BK) + { + ASSERTKS(B); + b = &konsts[B]; + } + else + { + ASSERTS(B); + b = ®.s[B]; + } + if (a & CMP_CK) + { + ASSERTKS(C); + c = &konsts[C]; + } + else + { + ASSERTS(C); + c = ®.s[C]; + } + test = (a & CMP_APPROX) ? b->CompareNoCase(*c) : b->Compare(*c); + method = a & CMP_METHOD_MASK; + if (method == CMP_EQ) + { + cmp = !test; + } + else if (method == CMP_LT) + { + cmp = (test < 0); + } + else + { + assert(method == CMP_LE); + cmp = (test <= 0); + } + if (cmp == (a & CMP_CHECK)) + { + assert(*pc == OP_JMP); + pc += 4 + JMPOFS(pc); + } + else + { + pc += 4; + } + } + NEXTOP; + + OP(SLL_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] << reg.d[C]; + NEXTOP; + OP(SLL_RI): + ASSERTD(a); ASSERTD(B); assert(0 <= C && C <= 31); + reg.d[a] = reg.d[B] << C; + NEXTOP; + OP(SLL_KR): + ASSERTD(a); ASSERTKD(B); ASSERTD(C); + reg.d[a] = konstd[B] << reg.d[C]; + NEXTOP; + + OP(SRL_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = (unsigned)reg.d[B] >> reg.d[C]; + NEXTOP; + OP(SRL_RI): + ASSERTD(a); ASSERTD(B); assert(0 <= C && C <= 31); + reg.d[a] = (unsigned)reg.d[B] >> C; + NEXTOP; + OP(SRL_KR): + ASSERTD(a); ASSERTKD(B); ASSERTD(C); + reg.d[a] = (unsigned)konstd[B] >> C; + NEXTOP; + + OP(SRA_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] >> reg.d[C]; + NEXTOP; + OP(SRA_RI): + ASSERTD(a); ASSERTD(B); assert(0 <= C && C <= 31); + reg.d[a] = reg.d[B] >> C; + NEXTOP; + OP(SRA_KR): + ASSERTD(a); ASSERTKD(B); ASSERTD(C); + reg.d[a] = konstd[B] >> reg.d[C]; + NEXTOP; + + OP(ADD_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] + reg.d[C]; + NEXTOP; + OP(ADD_RK): + ASSERTD(a); ASSERTD(B); ASSERTKD(C); + reg.d[a] = reg.d[B] + konstd[C]; + NEXTOP; + OP(ADDI): + ASSERTD(a); ASSERTD(B); + reg.d[a] = reg.d[B] + Cs; + NEXTOP; + + OP(SUB_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] - reg.d[C]; + NEXTOP; + OP(SUB_RK): + ASSERTD(a); ASSERTD(B); ASSERTKD(C); + reg.d[a] = reg.d[B] - konstd[C]; + NEXTOP; + OP(SUB_KR): + ASSERTD(a); ASSERTKD(B); ASSERTD(C); + reg.d[a] = konstd[B] - reg.d[C]; + NEXTOP; + + OP(MUL_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] * reg.d[C]; + NEXTOP; + OP(MUL_RK): + ASSERTD(a); ASSERTD(B); ASSERTKD(C); + reg.d[a] = reg.d[B] * konstd[C]; + NEXTOP; + + OP(DIV_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] / reg.d[C]; + NEXTOP; + OP(DIV_RK): + ASSERTD(a); ASSERTD(B); ASSERTKD(C); + reg.d[a] = reg.d[B] / konstd[C]; + NEXTOP; + OP(DIV_KR): + ASSERTD(a); ASSERTKD(B); ASSERTD(C); + reg.d[a] = konstd[B] / reg.d[C]; + NEXTOP; + + OP(MOD_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] % reg.d[C]; + NEXTOP; + OP(MOD_RK): + ASSERTD(a); ASSERTD(B); ASSERTKD(C); + reg.d[a] = reg.d[B] % konstd[C]; + NEXTOP; + OP(MOD_KR): + ASSERTD(a); ASSERTKD(B); ASSERTD(C); + reg.d[a] = konstd[B] % reg.d[C]; + NEXTOP; + + OP(AND_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] & reg.d[C]; + NEXTOP; + OP(AND_RK): + ASSERTD(a); ASSERTD(B); ASSERTKD(C); + reg.d[a] = reg.d[B] & konstd[C]; + NEXTOP; + + OP(OR_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] | reg.d[C]; + NEXTOP; + OP(OR_RK): + ASSERTD(a); ASSERTD(B); ASSERTKD(C); + reg.d[a] = reg.d[B] | konstd[C]; + NEXTOP; + + OP(XOR_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] ^ reg.d[C]; + NEXTOP; + OP(XOR_RK): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] ^ konstd[C]; + NEXTOP; + + OP(MIN_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] < reg.d[C] ? reg.d[B] : reg.d[C]; + NEXTOP; + OP(MIN_RK): + ASSERTD(a); ASSERTD(B); ASSERTKD(C); + reg.d[a] = reg.d[B] < konstd[C] ? reg.d[B] : konstd[C]; + NEXTOP; + OP(MAX_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] > reg.d[C] ? reg.d[B] : reg.d[C]; + NEXTOP; + OP(MAX_RK): + ASSERTD(a); ASSERTD(B); ASSERTKD(C); + reg.d[a] = reg.d[B] > konstd[C] ? reg.d[B] : konstd[C]; + NEXTOP; + + OP(ABS): + ASSERTD(a); ASSERTD(B); + reg.d[a] = abs(reg.d[B]); + NEXTOP; + + OP(NEG): + ASSERTD(a); ASSERTD(B); + reg.d[a] = -reg.d[B]; + NEXTOP; + + OP(NOT): + ASSERTD(a); ASSERTD(B); + reg.d[a] = ~reg.d[B]; + NEXTOP; + + OP(SEXT): + ASSERTD(a); ASSERTD(B); + reg.d[a] = (VM_SWORD)(reg.d[B] << C) >> C; + NEXTOP; + + OP(ZAP_R): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] & ZapTable[(reg.d[C] & 15) ^ 15]; + NEXTOP; + OP(ZAP_I): + ASSERTD(a); ASSERTD(B); + reg.d[a] = reg.d[B] & ZapTable[(C & 15) ^ 15]; + NEXTOP; + OP(ZAPNOT_R): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] & ZapTable[reg.d[C] & 15]; + NEXTOP; + OP(ZAPNOT_I): + ASSERTD(a); ASSERTD(B); + reg.d[a] = reg.d[B] & ZapTable[C & 15]; + NEXTOP; + + OP(EQ_R): + ASSERTD(B); ASSERTD(C); + CMPJMP(reg.d[B] == reg.d[C]); + NEXTOP; + OP(EQ_K): + ASSERTD(B); ASSERTKD(C); + CMPJMP(reg.d[B] == konstd[C]); + NEXTOP; + OP(LT_RR): + ASSERTD(B); ASSERTD(C); + CMPJMP(reg.d[B] < reg.d[C]); + NEXTOP; + OP(LT_RK): + ASSERTD(B); ASSERTKD(C); + CMPJMP(reg.d[B] < konstd[C]); + NEXTOP; + OP(LT_KR): + ASSERTKD(B); ASSERTD(C); + CMPJMP(konstd[B] < reg.d[C]); + NEXTOP; + OP(LE_RR): + ASSERTD(B); ASSERTD(C); + CMPJMP(reg.d[B] <= reg.d[C]); + NEXTOP; + OP(LE_RK): + ASSERTD(B); ASSERTKD(C); + CMPJMP(reg.d[B] <= konstd[C]); + NEXTOP; + OP(LE_KR): + ASSERTKD(B); ASSERTD(C); + CMPJMP(konstd[B] <= reg.d[C]); + NEXTOP; + OP(LTU_RR): + ASSERTD(B); ASSERTD(C); + CMPJMP((VM_UWORD)reg.d[B] < (VM_UWORD)reg.d[C]); + NEXTOP; + OP(LTU_RK): + ASSERTD(B); ASSERTKD(C); + CMPJMP((VM_UWORD)reg.d[B] < (VM_UWORD)konstd[C]); + NEXTOP; + OP(LTU_KR): + ASSERTKD(B); ASSERTD(C); + CMPJMP((VM_UWORD)konstd[B] < (VM_UWORD)reg.d[C]); + NEXTOP; + OP(LEU_RR): + ASSERTD(B); ASSERTD(C); + CMPJMP((VM_UWORD)reg.d[B] <= (VM_UWORD)reg.d[C]); + NEXTOP; + OP(LEU_RK): + ASSERTD(B); ASSERTKD(C); + CMPJMP((VM_UWORD)reg.d[B] <= (VM_UWORD)konstd[C]); + NEXTOP; + OP(LEU_KR): + ASSERTKD(B); ASSERTD(C); + CMPJMP((VM_UWORD)konstd[B] <= (VM_UWORD)reg.d[C]); + NEXTOP; + + OP(ADDF_RR): + ASSERTF(a); ASSERTF(B); ASSERTF(C); + reg.f[a] = reg.f[B] + reg.f[C]; + NEXTOP; + OP(ADDF_RK): + ASSERTF(a); ASSERTF(B); ASSERTKF(C); + reg.f[a] = reg.f[B] + konstf[C]; + NEXTOP; + + OP(SUBF_RR): + ASSERTF(a); ASSERTF(B); ASSERTF(C); + reg.f[a] = reg.f[B] - reg.f[C]; + NEXTOP; + OP(SUBF_RK): + ASSERTF(a); ASSERTF(B); ASSERTKF(C); + reg.f[a] = reg.f[B] - konstf[C]; + NEXTOP; + OP(SUBF_KR): + ASSERTF(a); ASSERTKF(B); ASSERTF(C); + reg.f[a] = konstf[B] - reg.f[C]; + NEXTOP; + + OP(MULF_RR): + ASSERTF(a); ASSERTF(B); ASSERTF(C); + reg.f[a] = reg.f[B] * reg.f[C]; + NEXTOP; + OP(MULF_RK): + ASSERTF(a); ASSERTF(B); ASSERTKF(C); + reg.f[a] = reg.f[B] * konstf[C]; + NEXTOP; + + OP(DIVF_RR): + ASSERTF(a); ASSERTF(B); ASSERTF(C); + reg.f[a] = reg.f[B] / reg.f[C]; + NEXTOP; + OP(DIVF_RK): + ASSERTF(a); ASSERTF(B); ASSERTKF(C); + reg.f[a] = reg.f[B] / konstf[C]; + NEXTOP; + OP(DIVF_KR): + ASSERTF(a); ASSERTKF(B); ASSERTF(C); + reg.f[a] = konstf[B] / reg.f[C]; + NEXTOP; + + OP(MODF_RR): + ASSERTF(a); ASSERTF(B); ASSERTF(C); + fb = reg.f[B]; fc = reg.f[C]; + Do_MODF: + reg.f[a] = luai_nummod(fb, fc); + NEXTOP; + OP(MODF_RK): + ASSERTF(a); ASSERTF(B); ASSERTKF(C); + fb = reg.f[B]; fc = konstf[C]; + goto Do_MODF; + NEXTOP; + OP(MODF_KR): + ASSERTF(a); ASSERTKF(B); ASSERTF(C); + fb = konstf[B]; fc = reg.f[C]; + goto Do_MODF; + NEXTOP; + + OP(POWF_RR): + ASSERTF(a); ASSERTF(B); ASSERTF(C); + reg.f[a] = pow(reg.f[B], reg.f[C]); + NEXTOP; + OP(POWF_RK): + ASSERTF(a); ASSERTF(B); ASSERTKF(C); + reg.f[a] = pow(reg.f[B], konstf[C]); + NEXTOP; + OP(POWF_KR): + ASSERTF(a); ASSERTKF(B); ASSERTF(C); + reg.f[a] = pow(konstf[B], reg.f[C]); + NEXTOP; + + OP(MINF_RR): + ASSERTF(a); ASSERTF(B); ASSERTF(C); + reg.f[a] = reg.f[B] < reg.f[C] ? reg.f[B] : reg.f[C]; + NEXTOP; + OP(MINF_RK): + ASSERTF(a); ASSERTF(B); ASSERTKF(C); + reg.f[a] = reg.f[B] < konstf[C] ? reg.f[B] : konstf[C]; + NEXTOP; + OP(MAXF_RR): + ASSERTF(a); ASSERTF(B); ASSERTF(C); + reg.f[a] = reg.f[B] > reg.f[C] ? reg.f[B] : reg.f[C]; + NEXTOP; + OP(MAXF_RK): + ASSERTF(a); ASSERTF(B); ASSERTKF(C); + reg.f[a] = reg.f[B] > konstf[C] ? reg.f[B] : konstf[C]; + NEXTOP; + + OP(FLOP): + ASSERTF(a); ASSERTF(B); + fb = reg.f[B]; + reg.f[a] = (C == FLOP_ABS) ? fabs(fb) : (C == FLOP_NEG) ? -fb : DoFLOP(C, fb); + NEXTOP; + + OP(EQF_R): + ASSERTF(B); ASSERTF(C); + if (a & CMP_APPROX) + { + CMPJMP(fabs(reg.f[C] - reg.f[B]) < VM_EPSILON); + } + else + { + CMPJMP(reg.f[C] == reg.f[B]); + } + NEXTOP; + OP(EQF_K): + ASSERTF(B); ASSERTKF(C); + if (a & CMP_APPROX) + { + CMPJMP(fabs(konstf[C] - reg.f[B]) < VM_EPSILON); + } + else + { + CMPJMP(konstf[C] == reg.f[B]); + } + NEXTOP; + OP(LTF_RR): + ASSERTF(B); ASSERTF(C); + if (a & CMP_APPROX) + { + CMPJMP((reg.f[B] - reg.f[C]) < -VM_EPSILON); + } + else + { + CMPJMP(reg.f[B] < reg.f[C]); + } + NEXTOP; + OP(LTF_RK): + ASSERTF(B); ASSERTKF(C); + if (a & CMP_APPROX) + { + CMPJMP((reg.f[B] - konstf[C]) < -VM_EPSILON); + } + else + { + CMPJMP(reg.f[B] < konstf[C]); + } + NEXTOP; + OP(LTF_KR): + ASSERTKF(B); ASSERTF(C); + if (a & CMP_APPROX) + { + CMPJMP((konstf[B] - reg.f[C]) < -VM_EPSILON); + } + else + { + CMPJMP(konstf[B] < reg.f[C]); + } + NEXTOP; + OP(LEF_RR): + ASSERTF(B); ASSERTF(C); + if (a & CMP_APPROX) + { + CMPJMP((reg.f[B] - reg.f[C]) <= -VM_EPSILON); + } + else + { + CMPJMP(reg.f[B] <= reg.f[C]); + } + NEXTOP; + OP(LEF_RK): + ASSERTF(B); ASSERTKF(C); + if (a & CMP_APPROX) + { + CMPJMP((reg.f[B] - konstf[C]) <= -VM_EPSILON); + } + else + { + CMPJMP(reg.f[B] <= konstf[C]); + } + NEXTOP; + OP(LEF_KR): + ASSERTKF(B); ASSERTF(C); + if (a & CMP_APPROX) + { + CMPJMP((konstf[B] - reg.f[C]) <= -VM_EPSILON); + } + else + { + CMPJMP(konstf[B] <= reg.f[C]); + } + NEXTOP; + + OP(NEGV): + ASSERTF(a+2); ASSERTF(B+2); + reg.f[a] = -reg.f[B]; + reg.f[a+1] = -reg.f[B+1]; + reg.f[a+2] = -reg.f[B+2]; + NEXTOP; + + OP(ADDV_RR): + ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C+2); + fcp = ®.f[C]; + Do_ADDV: + fbp = ®.f[B]; + reg.f[a] = fbp[0] + fcp[0]; + reg.f[a+1] = fbp[1] + fcp[1]; + reg.f[a+2] = fbp[2] + fcp[2]; + NEXTOP; + OP(ADDV_RK): + fcp = &konstf[C]; + goto Do_ADDV; + + OP(SUBV_RR): + ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C+2); + fbp = ®.f[B]; + fcp = ®.f[C]; + Do_SUBV: + reg.f[a] = fbp[0] - fcp[0]; + reg.f[a+1] = fbp[1] - fcp[1]; + reg.f[a+2] = fbp[2] - fcp[2]; + NEXTOP; + OP(SUBV_RK): + ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C+2); + fbp = ®.f[B]; + fcp = &konstf[C]; + goto Do_SUBV; + OP(SUBV_KR): + ASSERTF(A+2); ASSERTKF(B+2); ASSERTF(C+2); + fbp = &konstf[B]; + fcp = ®.f[C]; + goto Do_SUBV; + + OP(DOTV_RR): + ASSERTF(a); ASSERTF(B+2); ASSERTF(C+2); + reg.f[a] = reg.f[B] * reg.f[C] + reg.f[B+1] * reg.f[C+1] + reg.f[B+2] * reg.f[C+2]; + NEXTOP; + OP(DOTV_RK): + ASSERTF(a); ASSERTF(B+2); ASSERTKF(C+2); + reg.f[a] = reg.f[B] * konstf[C] + reg.f[B+1] * konstf[C+1] + reg.f[B+2] * konstf[C+2]; + NEXTOP; + + OP(CROSSV_RR): + ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C+2); + fbp = ®.f[B]; + fcp = ®.f[C]; + Do_CROSSV: + { + double t[3]; + t[2] = fbp[0] * fcp[1] - fbp[1] * fcp[0]; + t[1] = fbp[2] * fcp[0] - fbp[0] * fcp[2]; + t[0] = fbp[1] * fcp[2] - fbp[2] * fcp[1]; + reg.f[a] = t[0]; reg.f[a+1] = t[1]; reg.f[a+2] = t[2]; + } + NEXTOP; + OP(CROSSV_RK): + ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C+2); + fbp = ®.f[B]; + fcp = &konstf[C]; + goto Do_CROSSV; + OP(CROSSV_KR): + ASSERTF(a+2); ASSERTKF(B+2); ASSERTF(C+2); + fbp = ®.f[B]; + fcp = &konstf[C]; + goto Do_CROSSV; + + OP(MULVF_RR): + ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C); + fc = reg.f[C]; + fbp = ®.f[B]; + Do_MULV: + reg.f[a] = fbp[0] * fc; + reg.f[a+1] = fbp[1] * fc; + reg.f[a+2] = fbp[2] * fc; + NEXTOP; + OP(MULVF_RK): + ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C); + fc = konstf[C]; + fbp = ®.f[B]; + goto Do_MULV; + OP(MULVF_KR): + ASSERTF(a+2); ASSERTKF(B+2); ASSERTF(C); + fc = reg.f[C]; + fbp = &konstf[B]; + goto Do_MULV; + + OP(LENV): + ASSERTF(a); ASSERTF(B+2); + reg.f[a] = sqrt(reg.f[B] * reg.f[B] + reg.f[B+1] * reg.f[B+1] + reg.f[B+2] * reg.f[B+2]); + NEXTOP; + + OP(EQV_R): + ASSERTF(B+2); ASSERTF(C+2); + fcp = ®.f[C]; + Do_EQV: + if (a & CMP_APPROX) + { + CMPJMP(fabs(reg.f[B ] - fcp[0]) < VM_EPSILON && + fabs(reg.f[B+1] - fcp[1]) < VM_EPSILON && + fabs(reg.f[B+2] - fcp[2]) < VM_EPSILON); + } + else + { + CMPJMP(reg.f[B] == fcp[0] && reg.f[B+1] == fcp[1] && reg.f[B+2] == fcp[2]); + } + NEXTOP; + OP(EQV_K): + ASSERTF(B+2); ASSERTKF(C+2); + fcp = &konstf[C]; + goto Do_EQV; + + OP(ADDA_RR): + ASSERTA(a); ASSERTA(B); ASSERTD(C); + c = reg.d[C]; + Do_ADDA: + if (reg.a[B] == NULL) // Leave NULL pointers as NULL pointers + { + c = 0; + } + reg.a[a] = (VM_UBYTE *)reg.a[B] + c; + reg.atag[a] = c == 0 ? reg.atag[B] : ATAG_GENERIC; + NEXTOP; + OP(ADDA_RK): + ASSERTA(a); ASSERTA(B); ASSERTKD(C); + c = konstd[C]; + goto Do_ADDA; + + OP(SUBA): + ASSERTD(a); ASSERTA(B); ASSERTA(C); + reg.d[a] = (VM_UWORD)((VM_UBYTE *)reg.a[B] - (VM_UBYTE *)reg.a[C]); + NEXTOP; + + OP(EQA_R): + ASSERTA(B); ASSERTA(C); + CMPJMP(reg.a[B] == reg.a[C]); + NEXTOP; + OP(EQA_K): + ASSERTA(B); ASSERTKA(C); + CMPJMP(reg.a[B] == konsta[C]); + NEXTOP; + } + } + catch(VMException *exception) + { + // Try to find a handler for the exception. + PClass *extype = exception->GetClass(); + + while(--try_depth >= 0) + { + pc = exception_frames[try_depth]; + assert(pc[0] == OP_CATCH); + while (pc[1] > 1) + { + // CATCH must be followed by JMP if it doesn't terminate a catch chain. + assert(pc[4] == OP_JMP); + + PClass *type; + int b = pc[2]; + + if (pc[1] == 2) + { + ASSERTA(b); + type = (PClass *)reg.a[b]; + } + else + { + assert(pc[1] == 3); + ASSERTKA(b); + type = (PClass *)konsta[b]; + } + ASSERTA(pc[3]); + if (type == extype) + { + // Found a handler. Store the exception in pC, skip the JMP, + // and begin executing its code. + reg.a[pc[3]] = exception; + reg.atag[pc[3]] = ATAG_OBJECT; + pc += 8; + goto begin; + } + // This catch didn't handle it. Try the next one. + pc += 4 + JMPOFS(pc + 4); + assert(pc[0] == OP_CATCH); + } + if (pc[1] == 1) + { + // Catch any type of VMException. This terminates the chain. + ASSERTA(pc[3]); + reg.a[pc[3]] = exception; + reg.atag[pc[3]] = ATAG_OBJECT; + pc += 4; + goto begin; + } + // This frame failed. Try the next one out. + } + // Nothing caught it. Rethrow and let somebody else deal with it. + throw; + } + return 0; +} + +static double DoFLOP(int flop, double v) +{ + switch(flop) + { + case FLOP_ABS: return fabs(v); + case FLOP_NEG: return -v; + case FLOP_ACOS: return acos(v); + case FLOP_ASIN: return asin(v); + case FLOP_ATAN: return atan(v); + case FLOP_COS: return cos(v); + case FLOP_COSH: return cosh(v); + case FLOP_EXP: return exp(v); + case FLOP_LOG: return log(v); + case FLOP_LOG10: return log10(v); + case FLOP_SIN: return sin(v); + case FLOP_SINH: return sinh(v); + case FLOP_TAN: return tan(v); + case FLOP_TANH: return tanh(v); + case FLOP_SQRT: return sqrt(v); + case FLOP_CEIL: return ceil(v); + case FLOP_FLOOR: return floor(v); + } + assert(0); + return 0; +} + +static void DoCast(const VMRegisters ®, const VMFrame *f, int a, int b, int cast) +{ + switch (cast) + { + case CAST_I2F: + ASSERTF(a); ASSERTD(b); + reg.f[a] = reg.d[b]; + break; + case CAST_I2S: + ASSERTS(a); ASSERTD(b); + reg.s[a].Format("%d", reg.d[b]); + break; + + case CAST_F2I: + ASSERTD(a); ASSERTF(b); + reg.d[a] = (int)reg.f[b]; + break; + case CAST_F2S: + ASSERTS(a); ASSERTD(b); + reg.s[a].Format("%.14g", reg.f[b]); + break; + + case CAST_P2S: + ASSERTS(a); ASSERTA(b); + reg.s[a].Format("%s<%p>", reg.atag[b] == ATAG_OBJECT ? "Object" : "Pointer", reg.a[b]); + break; + + case CAST_S2I: + ASSERTD(a); ASSERTS(b); + reg.d[a] = (VM_SWORD)reg.s[b].ToLong(); + break; + case CAST_S2F: + ASSERTF(a); ASSERTS(b); + reg.f[a] = reg.s[b].ToDouble(); + break; + + default: + assert(0); + } +} + +//=========================================================================== +// +// FillReturns +// +// Fills in an array of pointers to locations to store return values in. +// +//=========================================================================== + +static void FillReturns(const VMRegisters ®, VMFrame *frame, VMReturn *returns, const VM_UBYTE *retval, int numret) +{ + int i, type, num; + VMReturn *ret; + + assert(REGT_INT == 0 && REGT_FLOAT == 1 && REGT_STRING == 2 && REGT_POINTER == 3); + + for (i = 0, ret = returns; i < numret; ++i, ++ret, retval += 4) + { + assert(retval[0] == OP_RESULT); // opcode + ret->RegType = type = retval[2]; + ret->RegNum = num = retval[3]; + assert(!(type & REGT_KONST)); + type &= REGT_TYPE; + if (type < REGT_STRING) + { + if (type == REGT_INT) + { + assert(num < frame->NumRegD); + ret->Location = ®.d[num]; + } + else // type == REGT_FLOAT + { + assert(num < frame->NumRegF); + ret->Location = ®.f[num]; + } + } + else if (type == REGT_STRING) + { + assert(num < frame->NumRegS); + ret->Location = ®.s[num]; + } + else + { + assert(type == REGT_POINTER); + assert(num < frame->NumRegA); + ret->Location = ®.a[num]; + } + } +} + +//=========================================================================== +// +// SetReturn +// +// Used by script code to set a return value. +// +//=========================================================================== + +static void SetReturn(const VMRegisters ®, VMFrame *frame, VMReturn *ret, VM_UBYTE regtype, int regnum) +{ + const void *src; + VM_UBYTE atag; + VMScriptFunction *func = static_cast<VMScriptFunction *>(frame->Func); + + assert(func != NULL && !func->Native); + assert((regtype & ~(REGT_KONST | REGT_FINAL)) == ret->RegType); + + switch (regtype & REGT_TYPE) + { + case REGT_INT: + assert(!(regtype & REGT_MULTIREG)); + if (regtype & REGT_KONST) + { + assert(regnum < func->NumKonstD); + src = &func->KonstD[regnum]; + } + else + { + assert(regnum < frame->NumRegD); + src = ®.d[regnum]; + } + ret->SetInt(*(int *)src); + break; + + case REGT_FLOAT: + if (regtype & REGT_KONST) + { + assert(regnum + ((regtype & REGT_KONST) ? 2u : 0u) < func->NumKonstF); + src = &func->KonstF[regnum]; + } + else + { + assert(regnum + ((regtype & REGT_KONST) ? 2u : 0u) < frame->NumRegF); + src = ®.f[regnum]; + } + if (regtype & REGT_MULTIREG) + { + ret->SetVector((double *)src); + } + else + { + ret->SetFloat(*(double *)src); + } + break; + + case REGT_STRING: + assert(!(regtype & REGT_MULTIREG)); + if (regtype & REGT_KONST) + { + assert(regnum < func->NumKonstS); + src = &func->KonstS[regnum]; + } + else + { + assert(regnum < frame->NumRegS); + src = ®.s[regnum]; + } + ret->SetString(*(const FString *)src); + break; + + case REGT_POINTER: + assert(!(regtype & REGT_MULTIREG)); + if (regtype & REGT_KONST) + { + assert(regnum < func->NumKonstA); + ret->SetPointer(func->KonstA[regnum]); + atag = ATAG_OBJECT; + } + else + { + assert(regnum < frame->NumRegA); + ret->SetPointer(reg.a[regnum]); + atag = reg.atag[regnum]; + } + if (ret->RegNum >= 0) + { + VMFrame *parent = frame->ParentFrame; + assert(parent != NULL); + parent->GetRegATag()[ret->RegNum] = atag; + } + break; + } +} diff --git a/zscript/vmframe.cpp b/zscript/vmframe.cpp new file mode 100644 index 000000000..208bc4725 --- /dev/null +++ b/zscript/vmframe.cpp @@ -0,0 +1,294 @@ +#include <new> +#include "vm.h" + + +//=========================================================================== +// +// VMFrame :: InitRegS +// +// Initialize the string registers of a newly-allocated VMFrame. +// +//=========================================================================== + +void VMFrame::InitRegS() +{ + FString *regs = GetRegS(); + for (int i = 0; i < NumRegS; ++i) + { + ::new(®s[i]) FString; + } +} + +//=========================================================================== +// +// VMFrameStack - Constructor +// +//=========================================================================== + +VMFrameStack::VMFrameStack() +{ + Blocks = NULL; + UnusedBlocks = NULL; +} + +//=========================================================================== +// +// VMFrameStack - Destructor +// +//=========================================================================== + +VMFrameStack::~VMFrameStack() +{ + while (PopFrame() != NULL) + { } + if (Blocks != NULL) + { + BlockHeader *block, *next; + for (block = Blocks; block != NULL; block = next) + { + next = block->NextBlock; + delete[] (VM_UBYTE *)block; + } + } + if (UnusedBlocks != NULL) + { + BlockHeader *block, *next; + for (block = UnusedBlocks; block != NULL; block = next) + { + next = block->NextBlock; + delete[] (VM_UBYTE *)block; + } + } + Blocks = NULL; + UnusedBlocks = NULL; +} + +//=========================================================================== +// +// VMFrameStack :: AllocFrame +// +// Allocates a frame from the stack with the desired number of registers. +// +//=========================================================================== + +VMFrame *VMFrameStack::AllocFrame(int numregd, int numregf, int numregs, int numrega) +{ + assert((unsigned)numregd < 255); + assert((unsigned)numregf < 255); + assert((unsigned)numregs < 255); + assert((unsigned)numrega < 255); + // To keep the arguments to this function simpler, it assumes that every + // register might be used as a parameter for a single call. + int numparam = numregd + numregf + numregs + numrega; + int size = VMFrame::FrameSize(numregd, numregf, numregs, numrega, numparam, 0); + VMFrame *frame = Alloc(size); + frame->NumRegD = numregd; + frame->NumRegF = numregf; + frame->NumRegS = numregs; + frame->NumRegA = numrega; + frame->MaxParam = numparam; + frame->InitRegS(); + return frame; +} + +//=========================================================================== +// +// VMFrameStack :: AllocFrame +// +// Allocates a frame from the stack suitable for calling a particular +// function. +// +//=========================================================================== + +VMFrame *VMFrameStack::AllocFrame(VMScriptFunction *func) +{ + int size = VMFrame::FrameSize(func->NumRegD, func->NumRegF, func->NumRegS, func->NumRegA, + func->MaxParam, func->ExtraSpace); + VMFrame *frame = Alloc(size); + frame->Func = func; + frame->NumRegD = func->NumRegD; + frame->NumRegF = func->NumRegF; + frame->NumRegS = func->NumRegS; + frame->NumRegA = func->NumRegA; + frame->MaxParam = func->MaxParam; + frame->Func = func; + frame->InitRegS(); + return frame; +} + +//=========================================================================== +// +// VMFrameStack :: Alloc +// +// Allocates space for a frame. Its size will be rounded up to a multiple +// of 16 bytes. +// +//=========================================================================== + +VMFrame *VMFrameStack::Alloc(int size) +{ + BlockHeader *block; + VMFrame *frame, *parent; + + size = (size + 15) & ~15; + block = Blocks; + if (block != NULL) + { + parent = block->LastFrame; + } + else + { + parent = NULL; + } + if (block == NULL || ((VM_UBYTE *)block + block->BlockSize) < (block->FreeSpace + size)) + { // Not enough space. Allocate a new block. + int blocksize = ((sizeof(BlockHeader) + 15) & ~15) + size; + BlockHeader **blockp; + if (blocksize < BLOCK_SIZE) + { + blocksize = BLOCK_SIZE; + } + for (blockp = &UnusedBlocks, block = *blockp; block != NULL; block = block->NextBlock) + { + if (block->BlockSize >= blocksize) + { + break; + } + } + if (block != NULL) + { + *blockp = block->NextBlock; + } + else + { + block = (BlockHeader *)new VM_UBYTE[blocksize]; + block->BlockSize = blocksize; + } + block->FreeSpace = (VM_UBYTE *)block + ((sizeof(BlockHeader) + 15) & ~15); + block->LastFrame = NULL; + block->NextBlock = Blocks; + Blocks = block; + } + frame = (VMFrame *)block->FreeSpace; + memset(frame, 0, size); + frame->ParentFrame = parent; + block->FreeSpace += size; + block->LastFrame = frame; + return frame; +} + + +//=========================================================================== +// +// VMFrameStack :: PopFrame +// +// Pops the top frame off the stack, returning a pointer to the new top +// frame. +// +//=========================================================================== + +VMFrame *VMFrameStack::PopFrame() +{ + if (Blocks == NULL) + { + return NULL; + } + VMFrame *frame = Blocks->LastFrame; + if (frame == NULL) + { + return NULL; + } + // Free any string registers this frame had. + FString *regs = frame->GetRegS(); + for (int i = frame->NumRegS; i != 0; --i) + { + (regs++)->~FString(); + } + // Free any parameters this frame left behind. + VMValue *param = frame->GetParam(); + for (int i = frame->NumParam; i != 0; --i) + { + (param++)->~VMValue(); + } + VMFrame *parent = frame->ParentFrame; + if (parent == NULL) + { + // Popping the last frame off the stack. + if (Blocks != NULL) + { + assert(Blocks->NextBlock == NULL); + Blocks->LastFrame = NULL; + Blocks->FreeSpace = (VM_UBYTE *)Blocks + ((sizeof(BlockHeader) + 15) & ~15); + } + return NULL; + } + if ((VM_UBYTE *)parent < (VM_UBYTE *)Blocks || (VM_UBYTE *)parent >= (VM_UBYTE *)Blocks + Blocks->BlockSize) + { // Parent frame is in a different block, so move this one to the unused list. + BlockHeader *next = Blocks->NextBlock; + assert(next != NULL); + assert((VM_UBYTE *)parent >= (VM_UBYTE *)next && (VM_UBYTE *)parent < (VM_UBYTE *)next + next->BlockSize); + Blocks->NextBlock = UnusedBlocks; + UnusedBlocks = Blocks; + Blocks = next; + } + else + { + Blocks->LastFrame = parent; + Blocks->FreeSpace = (VM_UBYTE *)frame; + } + return parent; +} + +//=========================================================================== +// +// VMFrameStack :: Call +// +// Calls a function, either native or scripted. If an exception occurs while +// executing, the stack is cleaned up. If trap is non-NULL, it is set to the +// VMException that was caught and the return value is negative. Otherwise, +// any caught exceptions will be rethrown. Under normal termination, the +// return value is the number of results from the function. +// +//=========================================================================== + +int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults, VMException **trap) +{ + bool allocated = false; + try + { + if (func->Native) + { + return static_cast<VMNativeFunction *>(func)->NativeCall(this, params, numparams, results, numresults); + } + else + { + AllocFrame(static_cast<VMScriptFunction *>(func)); + allocated = true; + VMFillParams(params, TopFrame(), numparams); + int numret = VMExec(this, static_cast<VMScriptFunction *>(func)->Code, results, numresults); + PopFrame(); + return numret; + } + } + catch (VMException *exception) + { + if (allocated) + { + PopFrame(); + } + if (trap != NULL) + { + *trap = exception; + return -1; + } + throw; + } + catch (...) + { + if (allocated) + { + PopFrame(); + } + throw; + } +} diff --git a/zscript/vmops.h b/zscript/vmops.h new file mode 100644 index 000000000..f7d821bb9 --- /dev/null +++ b/zscript/vmops.h @@ -0,0 +1,210 @@ +#ifndef xx +#define xx(op, name, mode) OP_##op +#endif + +// Load constants. +xx(LI, li, LI), // load immediate signed 16-bit constant +xx(LK, lk, LKI), // load integer constant +xx(LKF, lk, LKF), // load float constant +xx(LKS, lk, LKS), // load string constant +xx(LKP, lk, LKP), // load pointer constant +xx(LFP, lf, LFP), // load frame pointer + +// Load from memory. rA = *(rB + rkC) +xx(LB, lb, RIRPKI), // load byte +xx(LB_R, lb, RIRPRI), +xx(LH, lh, RIRPKI), // load halfword +xx(LH_R, lh, RIRPRI), +xx(LW, lw, RIRPKI), // load word +xx(LW_R, lw, RIRPRI), +xx(LBU, lbu, RIRPKI), // load byte unsigned +xx(LBU_R, lbu, RIRPRI), +xx(LHU, lhu, RIRPKI), // load halfword unsigned +xx(LHU_R, lhu, RIRPRI), +xx(LSP, lsp, RFRPKI), // load single-precision fp +xx(LSP_R, lsp, RFRPRI), +xx(LDP, ldp, RFRPKI), // load double-precision fp +xx(LDP_R, ldp, RFRPRI), +xx(LS, ls, RSRPKI), // load string +xx(LS_R, ls, RSRPRI), +xx(LO, lo, RPRPKI), // load object +xx(LO_R, lo, RPRPRI), +xx(LP, lp, RPRPKI), // load pointer +xx(LP_R, lp, RPRPRI), +xx(LV, lv, RVRPKI), // load vector +xx(LV_R, lv, RVRPRI), +xx(LX, lx, RFRPKI), // load fixed point +xx(LX_R, lx, RFRPRI), + +xx(LBIT, lbit, RIRPI8), // rA = !!(*rB & C) -- *rB is a byte + +// Store instructions. *(rA + rkC) = rB +xx(SB, sb, RPRIKI), // store byte +xx(SB_R, sb, RPRIRI), +xx(SH, sh, RPRIKI), // store halfword +xx(SH_R, sh, RPRIRI), +xx(SW, sw, RPRIKI), // store word +xx(SW_R, sw, RPRIRI), +xx(SSP, ssp, RPRFKI), // store single-precision fp +xx(SSP_R, ssp, RPRFRI), +xx(SDP, sdp, RPRFKI), // store double-precision fp +xx(SDP_R, sdp, RPRFRI), +xx(SS, ss, RPRSKI), // store string +xx(SS_R, ss, RPRSRI), +xx(SP, sp, RPRPKI), // store pointer +xx(SP_R, sp, RPRPRI), +xx(SV, sv, RPRVKI), // store vector +xx(SV_R, sv, RPRVRI), +xx(SX, sx, RPRFKI), // store fixed point +xx(SX_R, sx, RPRFRI), + +xx(SBIT, sbit, RPRII8), // *rA |= C if rB is true, *rA &= ~C otherwise + +// Move instructions. +xx(MOVE, mov, RIRI), // dA = dB +xx(MOVEF, mov, RFRF), // fA = fB +xx(MOVES, mov, RSRS), // sA = sB +xx(MOVEA, mov, RPRP), // aA = aB +xx(CAST, cast, CAST), // xA = xB, conversion specified by C +xx(DYNCAST_R, dyncast,RPRPRP), // aA = aB after casting to rkC (specifying a class) +xx(DYNCAST_K, dyncast,RPRPKP), + +// Control flow. +xx(TEST, test, RII16), // if (dA != BC) then pc++ +xx(JMP, jmp, I24), // pc += ABC -- The ABC fields contain a signed 24-bit offset. +xx(IJMP, ijmp, RII16), // pc += dA + BC -- BC is a signed offset. The target instruction must be a JMP. +xx(PARAM, param, __BCP), // push parameter encoded in BC for function call or result for return +xx(CALL, call, RPI8I8), // Call function pkA with parameter count B and expected result count C +xx(CALL_K, call, KPI8I8), +xx(RESULT, result, __BCP), // Result should go in register encoded in BC (in caller, after CALL) +xx(RET, ret, I8BCP), // Copy value from register encoded in BC to return value A, possibly returning +xx(TRY, try, I24), // When an exception is thrown, start searching for a handler at pc + ABC +xx(UNTRY, untry, I8), // Pop A entries off the exception stack +xx(THROW, throw, THROW), // A == 0: Throw exception object pB + // A != 0: Throw exception object pkB +xx(CATCH, catch, CATCH), // A == 0: continue search on next try + // A == 1: continue execution at instruction immediately following CATCH (catches any exception) + // A == 2: (pB == <type of exception thrown>) then pc++ ; next instruction must JMP to another CATCH + // A == 3: (pkB == <type of exception thrown>) then pc++ ; next instruction must JMP to another CATCH + // for A > 0, exception is stored in pC + +// String instructions. +xx(CONCAT, concat, RSRSRS), // sA = sB.. ... ..sC +xx(LENS, lens, RIRS), // dA = sB.Length +xx(CMPS, cmps, I8RXRX), // if ((skB op skC) != (A & 1)) then pc++ + +// Integer math. +xx(SLL_RR, sll, RIRIRI), // dA = dkB << diC +xx(SLL_RI, sll, RIRII8), +xx(SLL_KR, sll, RIKIRI), +xx(SRL_RR, srl, RIRIRI), // dA = dkB >> diC -- unsigned +xx(SRL_RI, srl, RIRII8), +xx(SRL_KR, srl, RIKIRI), +xx(SRA_RR, sra, RIRIRI), // dA = dkB >> diC -- signed +xx(SRA_RI, sra, RIRII8), +xx(SRA_KR, sra, RIKIRI), +xx(ADD_RR, add, RIRIRI), // dA = dB + dkC +xx(ADD_RK, add, RIRIKI), +xx(ADDI, add, RIRIIs), // dA = dB + C -- C is a signed 8-bit constant +xx(SUB_RR, sub, RIRIRI), // dA = dkB - dkC +xx(SUB_RK, sub, RIRIKI), +xx(SUB_KR, sub, RIKIRI), +xx(MUL_RR, mul, RIRIRI), // dA = dB * dkC +xx(MUL_RK, mul, RIRIKI), +xx(DIV_RR, div, RIRIRI), // dA = dkB / dkC +xx(DIV_RK, div, RIRIKI), +xx(DIV_KR, div, RIKIRI), +xx(MOD_RR, mod, RIRIRI), // dA = dkB % dkC +xx(MOD_RK, mod, RIRIKI), +xx(MOD_KR, mod, RIKIRI), +xx(AND_RR, and, RIRIRI), // dA = dB & dkC +xx(AND_RK, and, RIRIKI), +xx(OR_RR, or, RIRIRI), // dA = dB | dkC +xx(OR_RK, or, RIRIKI), +xx(XOR_RR, xor, RIRIRI), // dA = dB ^ dkC +xx(XOR_RK, xor, RIRIKI), +xx(MIN_RR, min, RIRIRI), // dA = min(dB,dkC) +xx(MIN_RK, min, RIRIKI), +xx(MAX_RR, max, RIRIRI), // dA = max(dB,dkC) +xx(MAX_RK, max, RIRIKI), +xx(ABS, abs, RIRI), // dA = abs(dB) +xx(NEG, neg, RIRI), // dA = -dB +xx(NOT, not, RIRI), // dA = !dB +xx(SEXT, sext, RIRII8), // dA = dB, sign extended by shifting left then right by C +xx(ZAP_R, zap, RIRIRI), // dA = dB, with bytes zeroed where bits in C/dC are one +xx(ZAP_I, zap, RIRII8), +xx(ZAPNOT_R, zapnot, RIRIRI), // dA = dB, with bytes zeroed where bits in C/dC are zero +xx(ZAPNOT_I, zapnot, RIRII8), +xx(EQ_R, eq, I8RIRI), // if ((dB == dkC) != A) then pc++ +xx(EQ_K, eq, I8RIKI), +xx(LT_RR, lt, I8RIRI), // if ((dkB < dkC) != A) then pc++ +xx(LT_RK, lt, I8RIKI), +xx(LT_KR, lt, I8KIRI), +xx(LE_RR, le, I8RIRI), // if ((dkB <= dkC) != A) then pc++ +xx(LE_RK, le, I8RIKI), +xx(LE_KR, le, I8KIRI), +xx(LTU_RR, ltu, I8RIRI), // if ((dkB < dkC) != A) then pc++ -- unsigned +xx(LTU_RK, ltu, I8RIKI), +xx(LTU_KR, ltu, I8KIRI), +xx(LEU_RR, leu, I8RIRI), // if ((dkB <= dkC) != A) then pc++ -- unsigned +xx(LEU_RK, leu, I8RIKI), +xx(LEU_KR, leu, I8KIRI), + +// Double-precision floating point math. +xx(ADDF_RR, add, RFRFRF), // fA = fB + fkC +xx(ADDF_RK, add, RFRFKF), +xx(SUBF_RR, sub, RFRFRF), // fA = fkB - fkC +xx(SUBF_RK, sub, RFRFKF), +xx(SUBF_KR, sub, RFKFRF), +xx(MULF_RR, mul, RFRFRF), // fA = fB * fkC +xx(MULF_RK, mul, RFRFKF), +xx(DIVF_RR, div, RFRFRF), // fA = fkB / fkC +xx(DIVF_RK, div, RFRFKF), +xx(DIVF_KR, div, RFKFRF), +xx(MODF_RR, mod, RFRFRF), // fA = fkB % fkC +xx(MODF_RK, mod, RFRFKF), +xx(MODF_KR, mod, RFKFRF), +xx(POWF_RR, pow, RFRFRF), // fA = fkB ** fkC +xx(POWF_RK, pow, RFRFKF), +xx(POWF_KR, pow, RFKFRF), +xx(MINF_RR, min, RFRFRF), // fA = min(fB),fkC) +xx(MINF_RK, min, RFRFKF), +xx(MAXF_RR, max, RFRFRF), // fA = max(fB),fkC) +xx(MAXF_RK, max, RFRFKF), +xx(FLOP, flop, RFRFI8), // fA = f(fB), where function is selected by C +xx(EQF_R, eq, I8RFRF), // if ((fB == fkC) != (A & 1)) then pc++ +xx(EQF_K, eq, I8RFKF), +xx(LTF_RR, lt, I8RFRF), // if ((fkB < fkC) != (A & 1)) then pc++ +xx(LTF_RK, lt, I8RFKF), +xx(LTF_KR, lt, I8KFRF), +xx(LEF_RR, le, I8RFRF), // if ((fkb <= fkC) != (A & 1)) then pc++ +xx(LEF_RK, le, I8RFKF), +xx(LEF_KR, le, I8KFRF), + +// Vector math. +xx(NEGV, negv, RVRV), // vA = -vB +xx(ADDV_RR, addv, RVRVRV), // vA = vB + vkC +xx(ADDV_RK, addv, RVRVKV), +xx(SUBV_RR, subv, RVRVRV), // vA = vkB - vkC +xx(SUBV_RK, subv, RVRVKV), +xx(SUBV_KR, subv, RVKVRV), +xx(DOTV_RR, dotv, RVRVRV), // va = vB dot vkC +xx(DOTV_RK, dotv, RVRVKV), +xx(CROSSV_RR, crossv, RVRVRV), // vA = vkB cross vkC +xx(CROSSV_RK, crossv, RVRVKV), +xx(CROSSV_KR, crossv, RVKVRV), +xx(MULVF_RR, mulv, RVRVRV), // vA = vkB * fkC +xx(MULVF_RK, mulv, RVRVKV), +xx(MULVF_KR, mulv, RVKVRV), +xx(LENV, lenv, RFRV), // fA = vB.Length +xx(EQV_R, eqv, I8RVRV), // if ((vB == vkC) != A) then pc++ (inexact if A & 32) +xx(EQV_K, eqv, I8RVKV), + +// Pointer math. +xx(ADDA_RR, add, RPRPRI), // pA = pB + dkC +xx(ADDA_RK, add, RPRPKI), +xx(SUBA, sub, RIRPRP), // dA = pB - pC +xx(EQA_R, eq, I8RPRP), // if ((pB == pkC) != A) then pc++ +xx(EQA_K, eq, I8RPKP), + +#undef xx From b7ad95446fe2201c896e3ef54dc64cce4aeea737 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 16 Sep 2009 02:53:05 +0000 Subject: [PATCH 002/232] - Fixed VMParamFiller to use proper A register tags. - Changed RET so that it will still work if the caller expects fewer return values. SVN r1843 (scripting) --- zscript/vm.h | 7 ++++--- zscript/vmexec.h | 9 ++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/zscript/vm.h b/zscript/vm.h index 8a8b9e9f8..ee20d3ceb 100644 --- a/zscript/vm.h +++ b/zscript/vm.h @@ -104,6 +104,7 @@ enum ATAG_SREGISTER, // pointer to a string register ATAG_AREGISTER, // pointer to an address register + ATAG_STATE, // pointer to FState }; class VMFunction : public DObject @@ -758,14 +759,14 @@ public: void ParamObject(DObject *obj) { Reg.a[RegA] = obj; - Reg.atag[RegA] = true; + Reg.atag[RegA] = ATAG_OBJECT; RegA++; } - void ParamPointer(void *ptr) + void ParamPointer(void *ptr, VM_UBTYE atag) { Reg.a[RegA] = ptr; - Reg.atag[RegA] = false; + Reg.atag[RegA] = atag; RegA++; } diff --git a/zscript/vmexec.h b/zscript/vmexec.h index c0b268589..6bb2ae3eb 100644 --- a/zscript/vmexec.h +++ b/zscript/vmexec.h @@ -533,11 +533,14 @@ begin: { // No return values return 0; } - assert(a < numret); - SetReturn(reg, f, &ret[a], B, C); + assert(ret != NULL || numret == 0); + if (a < numret) + { + SetReturn(reg, f, &ret[a], B, C); + } if (B & REGT_FINAL) { - return a + 1; + return MIN(numret, a + 1); } NEXTOP; OP(RESULT): From 92766165f530bca70f32d119352bcee33bd5e9eb Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 16 Sep 2009 03:01:40 +0000 Subject: [PATCH 003/232] OMG! Wrong directory! SVN r1844 (scripting) --- {zscript => src/zscript}/vm.h | 2 +- {zscript => src/zscript}/vmdisasm.cpp | 0 {zscript => src/zscript}/vmexec.cpp | 0 {zscript => src/zscript}/vmexec.h | 0 {zscript => src/zscript}/vmframe.cpp | 0 {zscript => src/zscript}/vmops.h | 0 zdoom.vcproj | 20 ++++++++++---------- 7 files changed, 11 insertions(+), 11 deletions(-) rename {zscript => src/zscript}/vm.h (94%) rename {zscript => src/zscript}/vmdisasm.cpp (100%) rename {zscript => src/zscript}/vmexec.cpp (100%) rename {zscript => src/zscript}/vmexec.h (100%) rename {zscript => src/zscript}/vmframe.cpp (100%) rename {zscript => src/zscript}/vmops.h (100%) diff --git a/zscript/vm.h b/src/zscript/vm.h similarity index 94% rename from zscript/vm.h rename to src/zscript/vm.h index ee20d3ceb..6755290c7 100644 --- a/zscript/vm.h +++ b/src/zscript/vm.h @@ -763,7 +763,7 @@ public: RegA++; } - void ParamPointer(void *ptr, VM_UBTYE atag) + void ParamPointer(void *ptr, VM_UBYTE atag) { Reg.a[RegA] = ptr; Reg.atag[RegA] = atag; diff --git a/zscript/vmdisasm.cpp b/src/zscript/vmdisasm.cpp similarity index 100% rename from zscript/vmdisasm.cpp rename to src/zscript/vmdisasm.cpp diff --git a/zscript/vmexec.cpp b/src/zscript/vmexec.cpp similarity index 100% rename from zscript/vmexec.cpp rename to src/zscript/vmexec.cpp diff --git a/zscript/vmexec.h b/src/zscript/vmexec.h similarity index 100% rename from zscript/vmexec.h rename to src/zscript/vmexec.h diff --git a/zscript/vmframe.cpp b/src/zscript/vmframe.cpp similarity index 100% rename from zscript/vmframe.cpp rename to src/zscript/vmframe.cpp diff --git a/zscript/vmops.h b/src/zscript/vmops.h similarity index 100% rename from zscript/vmops.h rename to src/zscript/vmops.h diff --git a/zdoom.vcproj b/zdoom.vcproj index a416fa6a8..9ee25f594 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -56,7 +56,7 @@ FavorSizeOrSpeed="1" OmitFramePointers="true" WholeProgramOptimization="false" - AdditionalIncludeDirectories="src\win32;src\sound;src;zlib;src\g_shared;src\g_doom;src\g_raven;src\g_heretic;src\g_hexen;src\g_strife;"jpeg-6b";game-music-emu\gme;gdtoa;bzip2;lzma\C" + AdditionalIncludeDirectories="src\zscript;src\win32;src\sound;src;zlib;src\g_shared;src\g_doom;src\g_raven;src\g_heretic;src\g_hexen;src\g_strife;"jpeg-6b";game-music-emu\gme;gdtoa;bzip2;lzma\C" PreprocessorDefinitions="NDEBUG,WIN32,_WIN32,_WINDOWS,HAVE_STRUPR,HAVE_FILELENGTH;NO_VA_COPY" StringPooling="true" ExceptionHandling="1" @@ -177,7 +177,7 @@ EnableIntrinsicFunctions="true" FavorSizeOrSpeed="1" OmitFramePointers="true" - AdditionalIncludeDirectories="src\win32;src\sound;src;zlib;src\g_shared;src\g_doom;src\g_raven;src\g_heretic;src\g_hexen;src\g_strife;"jpeg-6b";game-music-emu\gme;gdtoa;bzip2;lzma\C" + AdditionalIncludeDirectories="src\zscript;src\win32;src\sound;src;zlib;src\g_shared;src\g_doom;src\g_raven;src\g_heretic;src\g_hexen;src\g_strife;"jpeg-6b";game-music-emu\gme;gdtoa;bzip2;lzma\C" PreprocessorDefinitions="NDEBUG,WIN32,_WIN32,_WINDOWS,HAVE_STRUPR,HAVE_FILELENGTH;NO_VA_COPY" StringPooling="true" RuntimeLibrary="0" @@ -286,7 +286,7 @@ <Tool Name="VCCLCompilerTool" Optimization="0" - AdditionalIncludeDirectories="src\win32;src\sound;src;zlib;src\g_shared;src\g_doom;src\g_raven;src\g_heretic;src\g_hexen;src\g_strife;"jpeg-6b";game-music-emu\gme;gdtoa;bzip2;lzma\C" + AdditionalIncludeDirectories="src\zscript;src\win32;src\sound;src;zlib;src\g_shared;src\g_doom;src\g_raven;src\g_heretic;src\g_hexen;src\g_strife;"jpeg-6b";game-music-emu\gme;gdtoa;bzip2;lzma\C" PreprocessorDefinitions="WIN32,_DEBUG,_WIN32,_WINDOWS,_CRTDBG_MAP_ALLOC,HAVE_STRUPR,HAVE_FILELENGTH;NO_VA_COPY" MinimalRebuild="true" RuntimeLibrary="1" @@ -392,7 +392,7 @@ <Tool Name="VCCLCompilerTool" Optimization="0" - AdditionalIncludeDirectories="src\win32;src\sound;src;zlib;src\g_shared;src\g_doom;src\g_raven;src\g_heretic;src\g_hexen;src\g_strife;"jpeg-6b";game-music-emu\gme;gdtoa;bzip2;lzma\C" + AdditionalIncludeDirectories="src\zscript;src\win32;src\sound;src;zlib;src\g_shared;src\g_doom;src\g_raven;src\g_heretic;src\g_hexen;src\g_strife;"jpeg-6b";game-music-emu\gme;gdtoa;bzip2;lzma\C" PreprocessorDefinitions="WIN32,_DEBUG,_WIN32,_WINDOWS,_CRTDBG_MAP_ALLOC,HAVE_STRUPR,HAVE_FILELENGTH;NO_VA_COPY" MinimalRebuild="true" RuntimeLibrary="1" @@ -6450,27 +6450,27 @@ Name="ZScript" > <File - RelativePath=".\zscript\vm.h" + RelativePath=".\src\zscript\vm.h" > </File> <File - RelativePath=".\zscript\vmdisasm.cpp" + RelativePath=".\src\zscript\vmdisasm.cpp" > </File> <File - RelativePath=".\zscript\vmexec.cpp" + RelativePath=".\src\zscript\vmexec.cpp" > </File> <File - RelativePath=".\zscript\vmexec.h" + RelativePath=".\src\zscript\vmexec.h" > </File> <File - RelativePath=".\zscript\vmframe.cpp" + RelativePath=".\src\zscript\vmframe.cpp" > </File> <File - RelativePath=".\zscript\vmops.h" + RelativePath=".\src\zscript\vmops.h" > </File> </Filter> From 1eb7912bd835b460a62fb89ac937d6dc26c76c09 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Thu, 17 Sep 2009 01:36:14 +0000 Subject: [PATCH 004/232] - Make the autosegs read-only. - Derive PClass from dobject.cpp. This has one major ramification: Since the PClass is not allocated until runtime, you cannot initialize any static/global data structures with pointers to PClasses using RUNTIME_CLASS. Attempting to do so will just initialize with a NULL pointer. Instead, you can initialize using the address of the pointer returned by RUNTIME_CLASS and dereference that. By the time you have an opportunity to dereference it, it will no longer be NULL. - Sync CmakeLists.txt. - Random fixes for problems GCC spotted. SVN r1852 (scripting) --- src/CMakeLists.txt | 4 + src/autosegs.h | 2 +- src/autostart.cpp | 44 ++++++----- src/autozend.cpp | 33 ++++---- src/d_dehacked.cpp | 20 ++--- src/d_main.cpp | 6 -- src/decallib.h | 2 +- src/dobject.cpp | 6 +- src/dobject.h | 37 +++++---- src/dobjgc.cpp | 13 ++-- src/dobjtype.cpp | 109 +++++++++++++++++++-------- src/dobjtype.h | 10 ++- src/g_level.h | 4 +- src/g_shared/a_decals.cpp | 6 +- src/g_shared/a_morph.h | 2 +- src/info.cpp | 18 ++++- src/info.h | 18 ++--- src/m_cheat.cpp | 22 +++--- src/m_cheat.h | 2 +- src/p_buildmap.cpp | 4 +- src/p_enemy.h | 2 +- src/p_lnspec.cpp | 26 +++---- src/p_map.cpp | 2 +- src/p_spec.cpp | 2 +- src/p_terrain.h | 2 +- src/sdl/i_main.cpp | 1 + src/textures/textures.h | 2 +- src/thingdef/thingdef.h | 23 +++--- src/thingdef/thingdef_data.cpp | 22 +++--- src/thingdef/thingdef_expression.cpp | 3 - src/thingdef/thingdef_parse.cpp | 4 +- src/win32/i_main.cpp | 1 + src/zscript/vm.h | 7 +- src/zscript/vmexec.h | 2 +- wadsrc/static/actors/constants.txt | 4 - 35 files changed, 258 insertions(+), 207 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f7b8dd1ae..824d764a6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -771,6 +771,9 @@ add_executable( zdoom WIN32 timidity/resample.cpp timidity/timidity.cpp xlat/parse_xlat.cpp + zscript/vmdisasm.cpp + zscript/vmexec.cpp + zscript/vmframe.cpp autozend.cpp ) set_source_files_properties( xlat/parse_xlat.cpp PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c" ) @@ -790,6 +793,7 @@ include_directories( . thingdef timidity xlat + zscript ../game-music-emu/gme ../gdtoa ../dumb/include diff --git a/src/autosegs.h b/src/autosegs.h index fb3c0d3ee..b4f825879 100644 --- a/src/autosegs.h +++ b/src/autosegs.h @@ -36,7 +36,7 @@ #define AUTOSEGS_H #define REGMARKER(x) (x) -typedef void *REGINFO; +typedef void * const REGINFO; // List of Action functons extern REGINFO ARegHead; diff --git a/src/autostart.cpp b/src/autostart.cpp index 6ed85ae15..3822bafc1 100644 --- a/src/autostart.cpp +++ b/src/autostart.cpp @@ -46,24 +46,29 @@ #if defined(_MSC_VER) -#pragma comment(linker, "/merge:.areg=.data /merge:.creg=.data /merge:.greg=.data /merge:.mreg=.data /merge:.yreg=.data") +// The various reg sections are used to group pointers spread across multiple +// source files into cohesive arrays in the final executable. We don't +// actually care about these sections themselves and merge them all into +// a single section during the final link. (.rdata is the standard section +// for initialized read-only data.) -#pragma data_seg(".areg$a") -void *ARegHead = 0; +#pragma comment(linker, "/merge:.areg=.rdata /merge:.creg=.rdata /merge:.greg=.rdata") +#pragma comment(linker, "/merge:.mreg=.rdata /merge:.yreg=.rdata") -#pragma data_seg(".creg$a") -void *CRegHead = 0; +#pragma section(".areg$a",read) +__declspec(allocate(".areg$a")) void *const ARegHead = 0; -#pragma data_seg(".greg$a") -void *GRegHead = 0; +#pragma section(".creg$a",read) +__declspec(allocate(".creg$a")) void *const CRegHead = 0; -#pragma data_seg(".mreg$a") -void *MRegHead = 0; +#pragma section(".greg$a",read) +__declspec(allocate(".greg$a")) void *const GRegHead = 0; -#pragma data_seg(".yreg$a") -void *YRegHead = 0; +#pragma section(".mreg$a",read) +__declspec(allocate(".mreg$a")) void *const MRegHead = 0; -#pragma data_seg() +#pragma section(".yreg$a",read) +__declspec(allocate(".yreg$a")) void *const YRegHead = 0; // We want visual styles support under XP #if defined _M_IX86 @@ -88,11 +93,16 @@ void *YRegHead = 0; #include "doomtype.h" -void *ARegHead __attribute__((section(SECTION_AREG))) = 0; -void *CRegHead __attribute__((section(SECTION_CREG))) = 0; -void *GRegHead __attribute__((section(SECTION_GREG))) = 0; -void *MRegHead __attribute__((section(SECTION_MREG))) = 0; -void *YRegHead __attribute__((section(SECTION_YREG))) = 0; +// I don't know of an easy way to merge sections together with the GNU linker, +// so GCC users will see all of these sections appear in the final executable. +// (There are linker scripts, but that apparently involves extracting the +// default script from ld and then modifying it.) + +void *ARegHead const __attribute__((section(SECTION_AREG))) = 0; +void *CRegHead const __attribute__((section(SECTION_CREG))) = 0; +void *GRegHead const __attribute__((section(SECTION_GREG))) = 0; +void *MRegHead const __attribute__((section(SECTION_MREG))) = 0; +void *YRegHead const __attribute__((section(SECTION_YREG))) = 0; #else diff --git a/src/autozend.cpp b/src/autozend.cpp index 023f8c733..ab61bc92c 100644 --- a/src/autozend.cpp +++ b/src/autozend.cpp @@ -37,34 +37,31 @@ #if defined(_MSC_VER) -#pragma data_seg(".areg$z") -void *ARegTail = 0; +#pragma section(".areg$z",read) +__declspec(allocate(".areg$z")) void *const ARegTail = 0; -#pragma data_seg(".creg$z") -void *CRegTail = 0; +#pragma section(".creg$z",read) +__declspec(allocate(".creg$z")) void *const CRegTail = 0; -#pragma data_seg(".greg$z") -void *GRegTail = 0; +#pragma section(".greg$z",read) +__declspec(allocate(".greg$z")) void *const GRegTail = 0; -#pragma data_seg(".mreg$z") -void *MRegTail = 0; - -#pragma data_seg(".yreg$z") -void *YRegTail = 0; - -#pragma data_seg() +#pragma section(".mreg$z",read) +__declspec(allocate(".mreg$z")) void *const MRegTail = 0; +#pragma section(".yreg$z",read) +__declspec(allocate(".yreg$z")) void *const YRegTail = 0; #elif defined(__GNUC__) #include "doomtype.h" -void *ARegTail __attribute__((section(SECTION_AREG))) = 0; -void *CRegTail __attribute__((section(SECTION_CREG))) = 0; -void *GRegTail __attribute__((section(SECTION_GREG))) = 0; -void *MRegTail __attribute__((section(SECTION_MREG))) = 0; -void *YRegTail __attribute__((section(SECTION_YREG))) = 0; +void *const ARegTail __attribute__((section(SECTION_AREG))) = 0; +void *const CRegTail __attribute__((section(SECTION_CREG))) = 0; +void *const GRegTail __attribute__((section(SECTION_GREG))) = 0; +void *const MRegTail __attribute__((section(SECTION_MREG))) = 0; +void *const YRegTail __attribute__((section(SECTION_YREG))) = 0; #else diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 1ac3ff287..09fd3ba18 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -1760,16 +1760,16 @@ static int PatchMisc (int dummy) "Minotaur", NULL }; - static const PClass * const types[] = + static const PClass * const *types[] = { - RUNTIME_CLASS(APowerInvulnerable), - RUNTIME_CLASS(APowerStrength), - RUNTIME_CLASS(APowerInvisibility), - RUNTIME_CLASS(APowerIronFeet), - RUNTIME_CLASS(APowerLightAmp), - RUNTIME_CLASS(APowerWeaponLevel2), - RUNTIME_CLASS(APowerSpeed), - RUNTIME_CLASS(APowerMinotaur) + &RUNTIME_CLASS(APowerInvulnerable), + &RUNTIME_CLASS(APowerStrength), + &RUNTIME_CLASS(APowerInvisibility), + &RUNTIME_CLASS(APowerIronFeet), + &RUNTIME_CLASS(APowerLightAmp), + &RUNTIME_CLASS(APowerWeaponLevel2), + &RUNTIME_CLASS(APowerSpeed), + &RUNTIME_CLASS(APowerMinotaur) }; int i; @@ -1795,7 +1795,7 @@ static int PatchMisc (int dummy) } else { - static_cast<APowerup *>(GetDefaultByType (types[i]))->BlendColor = PalEntry( + static_cast<APowerup *>(GetDefaultByType (*types[i]))->BlendColor = PalEntry( BYTE(clamp(a,0.f,1.f)*255.f), clamp(r,0,255), clamp(g,0,255), diff --git a/src/d_main.cpp b/src/d_main.cpp index 7c0a13aca..9ade69c8e 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1691,12 +1691,10 @@ void D_DoomMain (void) execFiles = new DArgs; GameConfig->AddAutoexec (execFiles, GameNames[gameinfo.gametype]); D_MultiExec (execFiles, true); - execFiles->Destroy(); // Run .cfg files at the start of the command line. execFiles = Args->GatherFiles (NULL, ".cfg", false); D_MultiExec (execFiles, true); - execFiles->Destroy(); C_ExecCmdLineParams (); // [RH] do all +set commands on the command line @@ -1730,10 +1728,6 @@ void D_DoomMain (void) D_AddWildFile (files3->GetArg (i)); } } - files->Destroy(); - files1->Destroy(); - files2->Destroy(); - files3->Destroy(); Printf ("W_Init: Init WADfiles.\n"); Wads.InitMultipleFiles (&wadfiles); diff --git a/src/decallib.h b/src/decallib.h index 70804b0e5..61b97fc94 100644 --- a/src/decallib.h +++ b/src/decallib.h @@ -43,7 +43,7 @@ class FScanner; class FDecalTemplate; struct FDecalAnimator; -struct PClass; +class PClass; class DBaseDecal; struct side_t; diff --git a/src/dobject.cpp b/src/dobject.cpp index d71f87ed7..00ae9ee50 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -48,10 +48,9 @@ #include "a_sharedglobal.h" #include "dsectoreffect.h" -PClass DObject::_StaticType; ClassReg DObject::RegistrationInfo = { - &DObject::_StaticType, // MyClass + NULL, // MyClass "DObject", // Name NULL, // ParentType sizeof(DObject), // SizeOf @@ -458,9 +457,12 @@ size_t DObject::StaticPointerSubstitution (DObject *old, DObject *notOld) int i; // Go through all objects. + i = 0;DObject *last=0; for (probe = GC::Root; probe != NULL; probe = probe->ObjNext) { + i++; changed += probe->PointerSubstitution(old, notOld); + last = probe; } // Go through the bodyque. diff --git a/src/dobject.h b/src/dobject.h index 39ccbc576..8ed1f2352 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -37,7 +37,7 @@ #include <stdlib.h> #include "doomtype.h" -struct PClass; +class PClass; class FArchive; @@ -130,29 +130,28 @@ private: void CopyMeta (const FMetaTable *other); }; -#define RUNTIME_TYPE(object) (object->GetClass()) // Passed an object, returns the type of that object -#define RUNTIME_CLASS(cls) (&cls::_StaticType) // Passed a class name, returns a PClass representing that class -#define NATIVE_TYPE(object) (object->StaticType()) // Passed an object, returns the type of the C++ class representing the object +#define RUNTIME_TYPE(object) (object->GetClass()) // Passed an object, returns the type of that object +#define RUNTIME_CLASS(cls) (cls::RegistrationInfo.MyClass) // Passed a native class name, returns a PClass representing that class +#define NATIVE_TYPE(object) (object->StaticType()) // Passed an object, returns the type of the C++ class representing the object struct ClassReg { PClass *MyClass; const char *Name; - PClass *ParentType; + ClassReg *ParentType; unsigned int SizeOf; const size_t *Pointers; void (*ConstructNative)(void *); - void RegisterClass() const; + PClass *RegisterClass(); }; enum EInPlace { EC_InPlace }; #define DECLARE_ABSTRACT_CLASS(cls,parent) \ public: \ - static PClass _StaticType; \ - virtual PClass *StaticType() const { return &_StaticType; } \ - static ClassReg RegistrationInfo, *RegistrationInfoPtr; \ + virtual PClass *StaticType() const { return RegistrationInfo.MyClass; } \ + static ClassReg RegistrationInfo, * const RegistrationInfoPtr; \ private: \ typedef parent Super; \ typedef cls ThisClass; @@ -170,19 +169,17 @@ private: \ #define END_POINTERS ~(size_t)0 }; #if defined(_MSC_VER) -# pragma data_seg(".creg$u") -# pragma data_seg() -# define _DECLARE_TI(cls) __declspec(allocate(".creg$u")) ClassReg *cls::RegistrationInfoPtr = &cls::RegistrationInfo; +# pragma section(".creg$u",read) +# define _DECLARE_TI(cls) __declspec(allocate(".creg$u")) ClassReg * const cls::RegistrationInfoPtr = &cls::RegistrationInfo; #else -# define _DECLARE_TI(cls) ClassReg *cls::RegistrationInfoPtr __attribute__((section(SECTION_CREG))) = &cls::RegistrationInfo; +# define _DECLARE_TI(cls) ClassReg * const cls::RegistrationInfoPtr __attribute__((section(SECTION_CREG))) = &cls::RegistrationInfo; #endif #define _IMP_PCLASS(cls,ptrs,create) \ - PClass cls::_StaticType; \ ClassReg cls::RegistrationInfo = {\ - RUNTIME_CLASS(cls), \ + NULL, \ #cls, \ - RUNTIME_CLASS(cls::Super), \ + &cls::Super::RegistrationInfo, \ sizeof(cls), \ ptrs, \ create }; \ @@ -263,6 +260,9 @@ namespace GC // Size of GC steps. extern int StepMul; + // Is this the final collection just before exit? + extern bool FinalGC; + // Current white value for known-dead objects. static inline uint32 OtherWhite() { @@ -433,9 +433,8 @@ template<class T> inline void GC::Mark(TObjPtr<T> &obj) class DObject { public: - static PClass _StaticType; - virtual PClass *StaticType() const { return &_StaticType; } - static ClassReg RegistrationInfo, *RegistrationInfoPtr; + virtual PClass *StaticType() const { return RegistrationInfo.MyClass; } + static ClassReg RegistrationInfo, * const RegistrationInfoPtr; static void InPlaceConstructor (void *mem); private: typedef DObject ThisClass; diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index 0ba5d7c81..101729037 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -147,6 +147,7 @@ int Pause = DEFAULT_GCPAUSE; int StepMul = DEFAULT_GCMUL; int StepCount; size_t Dept; +bool FinalGC; // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -239,8 +240,8 @@ static DObject **SweepList(DObject **p, size_t count, size_t *finalize_count) // be in a thinker list, then I need to add write barriers for every time a // thinker pointer is changed. This seems easier and perfectly reasonable, since // a live thinker that isn't on a thinker list isn't much of a thinker. - assert(!curr->IsKindOf(RUNTIME_CLASS(DThinker)) || (curr->ObjectFlags & OF_Sentinel)); - assert(!curr->IsKindOf(RUNTIME_CLASS(DInterpolation))); + assert(FinalGC || !curr->IsKindOf(RUNTIME_CLASS(DThinker)) || (curr->ObjectFlags & OF_Sentinel)); + assert(FinalGC || !curr->IsKindOf(RUNTIME_CLASS(DInterpolation))); curr->Destroy(); } curr->ObjectFlags |= OF_Cleanup; @@ -327,14 +328,10 @@ static void MarkRoot() SectorMarker->SecNum = 0; } Mark(SectorMarker); - // Mark symbol tables + // Mark classes for (unsigned j = 0; j < PClass::m_Types.Size(); ++j) { - PClass *cls = PClass::m_Types[j]; - if (cls != NULL) - { - cls->Symbols.MarkSymbols(); - } + Mark(PClass::m_Types[j]); } // Mark bot stuff. Mark(bglobal.firstthing); diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 93586bcbf..d0e26b8ba 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -38,6 +38,10 @@ #include "templates.h" #include "autosegs.h" +IMPLEMENT_POINTY_CLASS(PClass) + DECLARE_POINTER(ParentClass) +END_POINTERS + TArray<PClass *> PClass::m_RuntimeActors; TArray<PClass *> PClass::m_Types; PClass *PClass::TypeHash[PClass::HASH_SIZE]; @@ -48,35 +52,29 @@ static const size_t TheEnd = ~(size_t)0; static int STACK_ARGS cregcmp (const void *a, const void *b) { - // VC++ introduces NULLs in the sequence. GCC seems to work as expected and not do it. - const ClassReg *class1 = *(const ClassReg **)a; - const ClassReg *class2 = *(const ClassReg **)b; - if (class1 == NULL) return 1; - if (class2 == NULL) return -1; - return strcmp (class1->Name, class2->Name); + const PClass *class1 = *(const PClass **)a; + const PClass *class2 = *(const PClass **)b; + return strcmp(class1->TypeName, class2->TypeName); } void PClass::StaticInit () { atterm (StaticShutdown); - // Sort classes by name to remove dependance on how the compiler ordered them. - REGINFO *head = &CRegHead; - REGINFO *tail = &CRegTail; - - // MinGW's linker is linking the object files backwards for me now... - if (head > tail) - { - swap (head, tail); - } - qsort (head + 1, tail - head - 1, sizeof(REGINFO), cregcmp); - FAutoSegIterator probe(CRegHead, CRegTail); while (*++probe != NULL) { ((ClassReg *)*probe)->RegisterClass (); } + + // Keep actors in consistant order. I did this before, though I'm not + // sure if this is really necessary to maintain any sort of sync. + qsort(&m_Types[0], m_Types.Size(), sizeof(m_Types[0]), cregcmp); + for (unsigned int i = 0; i < m_Types.Size(); ++i) + { + m_Types[i]->ClassIndex = i; + } } void PClass::StaticShutdown () @@ -114,6 +112,24 @@ void PClass::StaticShutdown () bShutdown = true; } +PClass::PClass() +{ + Size = sizeof(DObject); + ParentClass = NULL; + Pointers = NULL; + FlatPointers = NULL; + ActorInfo = NULL; + HashNext = NULL; + Defaults = NULL; + bRuntimeClass = false; + ClassIndex = ~0; +} + +PClass::~PClass() +{ + Symbols.ReleaseSymbols(); +} + void PClass::StaticFreeData (PClass *type) { if (type->Defaults != NULL) @@ -142,7 +158,7 @@ void PClass::StaticFreeData (PClass *type) } delete type->ActorInfo; type->ActorInfo = NULL; - } + }/* if (type->bRuntimeClass) { delete type; @@ -150,22 +166,32 @@ void PClass::StaticFreeData (PClass *type) else { type->Symbols.ReleaseSymbols(); - } + }*/ } -void ClassReg::RegisterClass () const +PClass *ClassReg::RegisterClass() { - assert (MyClass != NULL); + // MyClass may have already been created by a previous recursive call. + // Or this may be a recursive call for a previously created class. + if (MyClass != NULL) + { + return MyClass; + } // Add type to list - MyClass->ClassIndex = PClass::m_Types.Push (MyClass); - - MyClass->TypeName = FName(Name+1); - MyClass->ParentClass = ParentType; - MyClass->Size = SizeOf; - MyClass->Pointers = Pointers; - MyClass->ConstructNative = ConstructNative; - MyClass->InsertIntoHash (); + PClass *cls = new PClass; + MyClass = cls; + PClass::m_Types.Push(cls); + cls->TypeName = FName(Name+1); + if (ParentType != NULL) + { + cls->ParentClass = ParentType->RegisterClass(); + } + cls->Size = SizeOf; + cls->Pointers = Pointers; + cls->ConstructNative = ConstructNative; + cls->InsertIntoHash(); + return cls; } void PClass::InsertIntoHash () @@ -465,6 +491,28 @@ const PClass *PClass::NativeClass() const return cls; } +size_t PClass::PropagateMark() +{ + size_t marked; + + // Mark symbols + marked = Symbols.MarkSymbols(); + + // Mark state functions + if (ActorInfo != NULL) + { + for (int i = 0; i < ActorInfo->NumOwnedStates; ++i) + { + if (ActorInfo->OwnedStates[i].ActionFunc != NULL) + { + GC::Mark(ActorInfo->OwnedStates[i].ActionFunc); + } + } +// marked += ActorInfo->NumOwnedStates * sizeof(FState); + } + return marked + Super::PropagateMark(); +} + // Symbol tables ------------------------------------------------------------ IMPLEMENT_ABSTRACT_CLASS(PSymbol); @@ -486,12 +534,13 @@ PSymbolTable::~PSymbolTable () ReleaseSymbols(); } -void PSymbolTable::MarkSymbols() +size_t PSymbolTable::MarkSymbols() { for (unsigned int i = 0; i < Symbols.Size(); ++i) { GC::Mark(Symbols[i]); } + return Symbols.Size() * sizeof(Symbols[0]); } void PSymbolTable::ReleaseSymbols() diff --git a/src/dobjtype.h b/src/dobjtype.h index d58ce2f00..518f076c6 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -101,7 +101,7 @@ struct PSymbolTable PSymbolTable(); ~PSymbolTable(); - void MarkSymbols(); + size_t MarkSymbols(); // Sets the table to use for searches if this one doesn't contain the // requested symbol. @@ -126,8 +126,11 @@ private: // Meta-info for every class derived from DObject --------------------------- -struct PClass +class PClass : public DObject { + DECLARE_CLASS(PClass, DObject); + HAS_OBJECT_POINTERS; +public: static void StaticInit (); static void StaticShutdown (); static void StaticFreeData (PClass *type); @@ -149,6 +152,8 @@ struct PClass void (*ConstructNative)(void *); // The rest are all functions and static data ---------------- + PClass(); + ~PClass(); void InsertIntoHash (); DObject *CreateNew () const; PClass *CreateDerivedClass (FName name, unsigned int size); @@ -156,6 +161,7 @@ struct PClass void BuildFlatPointers (); void FreeStateList(); const PClass *NativeClass() const; + size_t PropagateMark(); // Returns true if this type is an ancestor of (or same as) the passed type. bool IsAncestorOf (const PClass *ti) const diff --git a/src/g_level.h b/src/g_level.h index 3b0851636..3f5186b1e 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -44,9 +44,7 @@ struct cluster_info_t; class FScanner; #if defined(_MSC_VER) -#pragma data_seg(".yreg$u") -#pragma data_seg() - +#pragma section(".yreg$u",read) #define MSVC_YSEG __declspec(allocate(".yreg$u")) #define GCC_YSEG #else diff --git a/src/g_shared/a_decals.cpp b/src/g_shared/a_decals.cpp index 77c036ba8..e1184c40c 100644 --- a/src/g_shared/a_decals.cpp +++ b/src/g_shared/a_decals.cpp @@ -357,7 +357,7 @@ fixed_t DBaseDecal::GetRealZ (const side_t *wall) const void DBaseDecal::CalcFracPos (side_t *wall, fixed_t x, fixed_t y) { - line_t *line = line = wall->linedef; + line_t *line = wall->linedef; vertex_t *v1, *v2; if (line->sidedef[0] == wall) @@ -390,7 +390,7 @@ void DBaseDecal::CalcFracPos (side_t *wall, fixed_t x, fixed_t y) static void GetWallStuff (side_t *wall, vertex_t *&v1, fixed_t &ldx, fixed_t &ldy) { - line_t *line = line = wall->linedef; + line_t *line = wall->linedef; if (line->sidedef[0] == wall) { v1 = line->v1; @@ -412,7 +412,7 @@ static fixed_t Length (fixed_t dx, fixed_t dy) static side_t *NextWall (const side_t *wall) { - line_t *line = line = wall->linedef;; + line_t *line = wall->linedef;; if (line->sidedef[0] == wall) { diff --git a/src/g_shared/a_morph.h b/src/g_shared/a_morph.h index 7ae83aed4..338b5f549 100644 --- a/src/g_shared/a_morph.h +++ b/src/g_shared/a_morph.h @@ -25,7 +25,7 @@ enum MORPH_UNDOBYDEATHSAVES = 0x00000800, // Actor (if unmorphed when killed) regains their health and doesn't die }; -struct PClass; +class PClass; class AActor; class player_t; class AMorphedMonster; diff --git a/src/info.cpp b/src/info.cpp index aeb89e8c9..cf12086ea 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -39,9 +39,8 @@ #include "m_fixed.h" #include "c_dispatch.h" #include "d_net.h" - #include "gi.h" - +#include "vm.h" #include "actor.h" #include "r_state.h" #include "i_system.h" @@ -52,6 +51,21 @@ extern void LoadActors (); +bool FState::CallAction(AActor *self, AActor *stateowner, StateCallData *statecall) +{ + if (ActionFunc != NULL) + { + //ActionFunc(self, stateowner, this, ParameterIndex-1, statecall); + VMFrameStack stack; + VMValue params[5] = { self, stateowner, this, ParameterIndex - 1, VMValue(statecall, ATAG_STATE) }; + stack.Call(ActionFunc, params, countof(params), NULL, 0, NULL); + return true; + } + else + { + return false; + } +} //========================================================================== // diff --git a/src/info.h b/src/info.h index 5e06bcc10..e4e73a5f8 100644 --- a/src/info.h +++ b/src/info.h @@ -43,6 +43,7 @@ #include "dobject.h" #include "doomdef.h" +#include "vm.h" const BYTE SF_FULLBRIGHT = 0x40; @@ -60,7 +61,7 @@ struct FState BYTE Frame; BYTE DefineFlags; // Unused byte so let's use it during state creation. FState *NextState; - actionf_p ActionFunc; + VMFunction *ActionFunc; int ParameterIndex; inline int GetFrame() const @@ -93,29 +94,20 @@ struct FState } void SetAction(PSymbolActionFunction *func, bool setdefaultparams = true) { +#if 0 if (func != NULL) { ActionFunc = func->Function; if (setdefaultparams) ParameterIndex = func->defaultparameterindex+1; } else +#endif { ActionFunc = NULL; if (setdefaultparams) ParameterIndex = 0; } } - inline bool CallAction(AActor *self, AActor *stateowner, StateCallData *statecall = NULL) - { - if (ActionFunc != NULL) - { - ActionFunc(self, stateowner, this, ParameterIndex-1, statecall); - return true; - } - else - { - return false; - } - } + bool CallAction(AActor *self, AActor *stateowner, StateCallData *statecall = NULL); static const PClass *StaticFindStateOwner (const FState *state); static const PClass *StaticFindStateOwner (const FState *state, const FActorInfo *info); }; diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index bcf36d45d..a4ffd5950 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -52,17 +52,17 @@ void cht_DoCheat (player_t *player, int cheat) { - static const PClass *BeholdPowers[9] = + static const PClass *const *BeholdPowers[9] = { - RUNTIME_CLASS(APowerInvulnerable), - RUNTIME_CLASS(APowerStrength), - RUNTIME_CLASS(APowerInvisibility), - RUNTIME_CLASS(APowerIronFeet), + &RUNTIME_CLASS(APowerInvulnerable), + &RUNTIME_CLASS(APowerStrength), + &RUNTIME_CLASS(APowerInvisibility), + &RUNTIME_CLASS(APowerIronFeet), NULL, // MapRevealer - RUNTIME_CLASS(APowerLightAmp), - RUNTIME_CLASS(APowerShadow), - RUNTIME_CLASS(APowerMask), - RUNTIME_CLASS(APowerTargeter) + &RUNTIME_CLASS(APowerLightAmp), + &RUNTIME_CLASS(APowerShadow), + &RUNTIME_CLASS(APowerMask), + &RUNTIME_CLASS(APowerTargeter) }; const PClass *type; AInventory *item; @@ -248,12 +248,12 @@ void cht_DoCheat (player_t *player, int cheat) } else if (player->mo != NULL && player->health >= 0) { - item = player->mo->FindInventory (BeholdPowers[i]); + item = player->mo->FindInventory (*BeholdPowers[i]); if (item == NULL) { if (i != 0) { - player->mo->GiveInventoryType (BeholdPowers[i]); + player->mo->GiveInventoryType (*BeholdPowers[i]); if (cheat == CHT_BEHOLDS) { P_GiveBody (player->mo, -100); diff --git a/src/m_cheat.h b/src/m_cheat.h index d273965ae..e56c69198 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -29,7 +29,7 @@ // [RH] Functions that actually perform the cheating class player_t; -struct PClass; +class PClass; void cht_DoCheat (player_t *player, int cheat); void cht_Give (player_t *player, const char *item, int amount=1); void cht_Take (player_t *player, const char *item, int amount=1); diff --git a/src/p_buildmap.cpp b/src/p_buildmap.cpp index 4e44e1c26..8cf3273e1 100644 --- a/src/p_buildmap.cpp +++ b/src/p_buildmap.cpp @@ -624,11 +624,11 @@ static void LoadWalls (walltype *walls, int numwalls, sectortype *bsec) int sidenum = int(intptr_t(lines[linenum].sidedef[1])); if (bsec->floorstat & 64) { // floor is aligned to first wall - R_AlignFlat (linenum, sidenum == (DWORD)bsec->wallptr, 0); + R_AlignFlat (linenum, (DWORD)sidenum == (DWORD)bsec->wallptr, 0); } if (bsec->ceilingstat & 64) { // ceiling is aligned to first wall - R_AlignFlat (linenum, sidenum == (DWORD)bsec->wallptr, 0); + R_AlignFlat (linenum, (DWORD)sidenum == (DWORD)bsec->wallptr, 0); } } for(i = 0; i < numsides; i++) diff --git a/src/p_enemy.h b/src/p_enemy.h index f111f9d08..73fe06e3d 100644 --- a/src/p_enemy.h +++ b/src/p_enemy.h @@ -6,7 +6,7 @@ struct sector_t; class AActor; class AInventory; -struct PClass; +class PClass; enum dirtype_t diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index b34ed4878..8615ffcac 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -2504,19 +2504,19 @@ FUNC(LS_SetPlayerProperty) // Add or remove a power if (arg2 >= PROP_INVULNERABILITY && arg2 <= PROP_SPEED) { - static const PClass *powers[11] = + static const PClass * const *powers[11] = { - RUNTIME_CLASS(APowerInvulnerable), - RUNTIME_CLASS(APowerStrength), - RUNTIME_CLASS(APowerInvisibility), - RUNTIME_CLASS(APowerIronFeet), + &RUNTIME_CLASS(APowerInvulnerable), + &RUNTIME_CLASS(APowerStrength), + &RUNTIME_CLASS(APowerInvisibility), + &RUNTIME_CLASS(APowerIronFeet), NULL, // MapRevealer - RUNTIME_CLASS(APowerLightAmp), - RUNTIME_CLASS(APowerWeaponLevel2), - RUNTIME_CLASS(APowerFlight), + &RUNTIME_CLASS(APowerLightAmp), + &RUNTIME_CLASS(APowerWeaponLevel2), + &RUNTIME_CLASS(APowerFlight), NULL, NULL, - RUNTIME_CLASS(APowerSpeed) + &RUNTIME_CLASS(APowerSpeed) }; int power = arg2 - PROP_INVULNERABILITY; @@ -2531,7 +2531,7 @@ FUNC(LS_SetPlayerProperty) { // Give power to activator if (power != 4) { - APowerup *item = static_cast<APowerup*>(it->GiveInventoryType (powers[power])); + APowerup *item = static_cast<APowerup*>(it->GiveInventoryType (*powers[power])); if (item != NULL && power == 0) item->BlendColor = INVERSECOLOR; } else if (it->player - players == consoleplayer) @@ -2543,7 +2543,7 @@ FUNC(LS_SetPlayerProperty) { // Take power from activator if (power != 4) { - AInventory *item = it->FindInventory (powers[power]); + AInventory *item = it->FindInventory (*powers[power]); if (item != NULL) { item->Destroy (); @@ -2568,7 +2568,7 @@ FUNC(LS_SetPlayerProperty) { // Give power if (power != 4) { - players[i].mo->GiveInventoryType (powers[power]); + players[i].mo->GiveInventoryType (*powers[power]); } else if (i == consoleplayer) { @@ -2579,7 +2579,7 @@ FUNC(LS_SetPlayerProperty) { // Take power if (power != 4) { - AInventory *item = players[i].mo->FindInventory (powers[power]); + AInventory *item = players[i].mo->FindInventory (*powers[power]); if (item != NULL) { item->Destroy (); diff --git a/src/p_map.cpp b/src/p_map.cpp index 09dbf076b..b32c9e3ad 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4906,7 +4906,7 @@ msecnode_t *P_AddSecnode (sector_t *s, AActor *thing, msecnode_t *nextnode) if (s == 0) { - I_FatalError ("AddSecnode of 0 for %s\n", thing->_StaticType.TypeName.GetChars()); + I_FatalError ("AddSecnode of 0 for %s\n", thing->GetClass()->TypeName.GetChars()); } node = nextnode; diff --git a/src/p_spec.cpp b/src/p_spec.cpp index e1d486869..c7e792908 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -1332,7 +1332,7 @@ static void P_SpawnScrollers(void) if (special != 0) { int max = LineSpecialsInfo[special] != NULL ? LineSpecialsInfo[special]->map_args : countof(l->args); - for (int arg = max; arg < countof(l->args); ++arg) + for (int arg = max; arg < (int)countof(l->args); ++arg) { if (l->args[arg] != 0) { diff --git a/src/p_terrain.h b/src/p_terrain.h index 087087afe..e5a98ccf8 100644 --- a/src/p_terrain.h +++ b/src/p_terrain.h @@ -37,7 +37,7 @@ #include "s_sound.h" #include "textures/textures.h" -struct PClass; +class PClass; // This is just a wrapper class so that I don't have to expose FTextureID's implementation // to anything that doesn't really need it. diff --git a/src/sdl/i_main.cpp b/src/sdl/i_main.cpp index 5650c0781..7a80d9fc2 100644 --- a/src/sdl/i_main.cpp +++ b/src/sdl/i_main.cpp @@ -140,6 +140,7 @@ void STACK_ARGS call_terms () static void FinalGC() { + GC::FinalGC = true; Args = NULL; GC::FullGC(); } diff --git a/src/textures/textures.h b/src/textures/textures.h index c96da0648..195295a5c 100644 --- a/src/textures/textures.h +++ b/src/textures/textures.h @@ -7,7 +7,7 @@ class FBitmap; struct FRemapTable; struct FCopyInfo; class FScanner; -struct PClass; +class PClass; class FArchive; // Texture IDs diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index df4bc78ab..2f573f8e9 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -243,10 +243,9 @@ enum EDefinitionType }; #if defined(_MSC_VER) -#pragma data_seg(".areg$u") -#pragma data_seg(".greg$u") -#pragma data_seg(".mreg$u") -#pragma data_seg() +#pragma section(".areg$u",read) +#pragma section(".greg$u",read) +#pragma section(".mreg$u",read) #define MSVC_ASEG __declspec(allocate(".areg$u")) #define GCC_ASEG @@ -283,7 +282,7 @@ struct FPropertyInfo { const char *name; const char *params; - const PClass *cls; + const PClass * const *cls; PropHandler Handler; int category; }; @@ -292,7 +291,7 @@ struct FVariableInfo { const char *name; intptr_t address; - const PClass *owner; + const PClass * const *owner; }; @@ -304,14 +303,14 @@ int MatchString (const char *in, const char **strings); #define DEFINE_PROPERTY_BASE(name, paramlist, clas, cat) \ static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, FActorInfo *info, Baggage &bag, FPropParam *params); \ static FPropertyInfo Prop_##name##_##paramlist##_##clas = \ - { #name, #paramlist, RUNTIME_CLASS(A##clas), (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \ + { #name, #paramlist, &RUNTIME_CLASS(A##clas), (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \ MSVC_PSEG FPropertyInfo *infoptr_##name##_##paramlist##_##clas GCC_PSEG = &Prop_##name##_##paramlist##_##clas; \ static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, FActorInfo *info, Baggage &bag, FPropParam *params) #define DEFINE_PREFIXED_PROPERTY_BASE(prefix, name, paramlist, clas, cat) \ static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, FActorInfo *info, Baggage &bag, FPropParam *params); \ static FPropertyInfo Prop_##name##_##paramlist##_##clas = \ -{ #prefix"."#name, #paramlist, RUNTIME_CLASS(A##clas), (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \ +{ #prefix"."#name, #paramlist, &RUNTIME_CLASS(A##clas), (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \ MSVC_PSEG FPropertyInfo *infoptr_##name##_##paramlist##_##clas GCC_PSEG = &Prop_##name##_##paramlist##_##clas; \ static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, FActorInfo *info, Baggage &bag, FPropParam *params) @@ -340,16 +339,12 @@ int MatchString (const char *in, const char **strings); int var = params[(no)+1].i== 0? params[(no)+2].i : V_GetColor(NULL, params[(no)+2].s); -#define DEFINE_GLOBAL_VARIABLE(name) \ - static FVariableInfo GlobalDef__##name = { #name, intptr_t(&name), NULL }; \ - MSVC_MSEG FVariableInfo *infoptr_GlobalDef__##name GCC_MSEG = &GlobalDef__##name; - #define DEFINE_MEMBER_VARIABLE(name, cls) \ - static FVariableInfo GlobalDef__##name = { #name, myoffsetof(cls, name), RUNTIME_CLASS(cls) }; \ + static FVariableInfo GlobalDef__##name = { #name, myoffsetof(cls, name), &RUNTIME_CLASS(cls) }; \ MSVC_MSEG FVariableInfo *infoptr_GlobalDef__##name GCC_MSEG = &GlobalDef__##name; #define DEFINE_MEMBER_VARIABLE_ALIAS(name, alias, cls) \ - static FVariableInfo GlobalDef__##name = { #name, myoffsetof(cls, alias), RUNTIME_CLASS(cls) }; \ + static FVariableInfo GlobalDef__##name = { #name, myoffsetof(cls, alias), &RUNTIME_CLASS(cls) }; \ MSVC_MSEG FVariableInfo *infoptr_GlobalDef__##name GCC_MSEG = &GlobalDef__##name; diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index c65cb5d21..b23852365 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -311,12 +311,12 @@ static FFlagDef PlayerPawnFlags[] = DEFINE_FLAG(PPF, NOTHRUSTWHENINVUL, APlayerPawn, PlayerFlags), }; -static const struct FFlagList { const PClass *Type; FFlagDef *Defs; int NumDefs; } FlagLists[] = +static const struct FFlagList { const PClass * const *Type; FFlagDef *Defs; int NumDefs; } FlagLists[] = { - { RUNTIME_CLASS(AActor), ActorFlags, countof(ActorFlags) }, - { RUNTIME_CLASS(AInventory), InventoryFlags, countof(InventoryFlags) }, - { RUNTIME_CLASS(AWeapon), WeaponFlags, countof(WeaponFlags) }, - { RUNTIME_CLASS(APlayerPawn), PlayerPawnFlags,countof(PlayerPawnFlags) }, + { &RUNTIME_CLASS(AActor), ActorFlags, countof(ActorFlags) }, + { &RUNTIME_CLASS(AInventory), InventoryFlags, countof(InventoryFlags) }, + { &RUNTIME_CLASS(AWeapon), WeaponFlags, countof(WeaponFlags) }, + { &RUNTIME_CLASS(APlayerPawn), PlayerPawnFlags,countof(PlayerPawnFlags) }, }; #define NUM_FLAG_LISTS (countof(FlagLists)) @@ -364,7 +364,7 @@ FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2) { // Search all lists for (i = 0; i < NUM_FLAG_LISTS; ++i) { - if (type->IsDescendantOf (FlagLists[i].Type)) + if (type->IsDescendantOf (*FlagLists[i].Type)) { def = FindFlag (FlagLists[i].Defs, FlagLists[i].NumDefs, part1); if (def != NULL) @@ -378,9 +378,9 @@ FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2) { // Search just the named list for (i = 0; i < NUM_FLAG_LISTS; ++i) { - if (stricmp (FlagLists[i].Type->TypeName.GetChars(), part1) == 0) + if (stricmp ((*FlagLists[i].Type)->TypeName.GetChars(), part1) == 0) { - if (type->IsDescendantOf (FlagLists[i].Type)) + if (type->IsDescendantOf (*FlagLists[i].Type)) { return FindFlag (FlagLists[i].Defs, FlagLists[i].NumDefs, part2); } @@ -403,7 +403,7 @@ FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2) const char *GetFlagName(int flagnum, int flagoffset) { - for(int i=0; i<countof(ActorFlags); i++) + for(size_t i = 0; i < countof(ActorFlags); i++) { if (ActorFlags[i].flagbit == flagnum && ActorFlags[i].structoffset == flagoffset) { @@ -489,8 +489,8 @@ FVariableInfo *FindVariable(const char * string, const PClass *cls) int mid = (min + max) / 2; int lexval; - if (cls < variables[mid]->owner) lexval = -1; - else if (cls > variables[mid]->owner) lexval = 1; + if (cls < *variables[mid]->owner) lexval = -1; + else if (cls > *variables[mid]->owner) lexval = 1; else lexval = stricmp (string, variables[mid]->name); if (lexval == 0) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index d68ecfcd6..60a01586b 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -50,9 +50,6 @@ #include "doomstat.h" #include "thingdef_exp.h" -int testglobalvar = 1337; // just for having one global variable to test with -DEFINE_GLOBAL_VARIABLE(testglobalvar) - // Accessible actor member variables DEFINE_MEMBER_VARIABLE(alpha, AActor) DEFINE_MEMBER_VARIABLE(angle, AActor) diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 039d578b4..160555f46 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -733,13 +733,13 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag) if (prop != NULL) { - if (bag.Info->Class->IsDescendantOf(prop->cls)) + if (bag.Info->Class->IsDescendantOf(*prop->cls)) { ParsePropertyParams(sc, prop, (AActor *)bag.Info->Class->Defaults, bag); } else { - sc.ScriptMessage("\"%s\" requires an actor of type \"%s\"\n", propname.GetChars(), prop->cls->TypeName.GetChars()); + sc.ScriptMessage("\"%s\" requires an actor of type \"%s\"\n", propname.GetChars(), (*prop->cls)->TypeName.GetChars()); FScriptPosition::ErrorCounter++; } } diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp index 6bc9e2f5f..5f2383fee 100644 --- a/src/win32/i_main.cpp +++ b/src/win32/i_main.cpp @@ -262,6 +262,7 @@ static void UnWTS (void) static void FinalGC() { + GC::FinalGC = true; Args = NULL; GC::FullGC(); } diff --git a/src/zscript/vm.h b/src/zscript/vm.h index 6755290c7..61207e862 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -409,13 +409,12 @@ struct VMValue Type = REGT_POINTER; return *this; } - VMValue &operator=(void *v) + void SetPointer(void *v, VM_UBYTE atag=ATAG_GENERIC) { Kill(); a = v; - atag = ATAG_GENERIC; - Type = REGT_POINTER; - return *this; + atag = atag; + Type = atag; } void SetNil() { diff --git a/src/zscript/vmexec.h b/src/zscript/vmexec.h index 6bb2ae3eb..ec41b3ac8 100644 --- a/src/zscript/vmexec.h +++ b/src/zscript/vmexec.h @@ -540,7 +540,7 @@ begin: } if (B & REGT_FINAL) { - return MIN(numret, a + 1); + return a < numret ? a + 1 : numret; } NEXTOP; OP(RESULT): diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index f69771f25..c3a65e025 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -99,7 +99,3 @@ const float ATTN_NONE = 0; const float ATTN_NORM = 1; const float ATTN_IDLE = 1.001; const float ATTN_STATIC = 3; - - -// This is only here to provide one global variable for testing. -native int testglobalvar; From 3e7b69a12eb411803182a48e11ec25b561d62953 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 23 Sep 2009 00:23:24 +0000 Subject: [PATCH 005/232] - All states now use thunk functions to call the action functions. This is the bare minimum to be able to say that VM is being used. - Added tags for the pointer constants table. SVN r1871 (scripting) --- src/info.cpp | 66 ++++++++++++++++++++++++++++++ src/info.h | 16 +------- src/zscript/vm.h | 51 +++++++++++++++++------ src/zscript/vmexec.h | 28 ++++++++----- src/zscript/vmframe.cpp | 89 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 211 insertions(+), 39 deletions(-) diff --git a/src/info.cpp b/src/info.cpp index cf12086ea..8f36ffac4 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -51,6 +51,72 @@ extern void LoadActors (); +int CallDecorateAction(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) +{ + assert(numparam == 6); + actionf_p action = (actionf_p)param[5].a; + action((AActor *)param[0].a, (AActor *)param[1].a, (FState *)param[2].a, param[3].i, (StateCallData *)param[4].a); + return 0; +} + +void FState::SetAction(PSymbolActionFunction *func, bool setdefaultparams) +{ + if (func != NULL) + { + // All generated functions use this code. + static const VM_UBYTE codetemplate[] = + { + OP_PARAM, 0, REGT_POINTER, 0, + OP_PARAM, 0, REGT_POINTER, 1, + OP_PARAM, 0, REGT_POINTER, 2, + OP_PARAM, 0, REGT_INT, 0, + OP_PARAM, 0, REGT_POINTER, 3, + OP_PARAM, 0, REGT_POINTER|REGT_KONST, 0, + OP_CALL_K, 1, 6, 0, + OP_RET, 0, REGT_NIL, 0 + }; + + // Find the CallDecorateAction function. If not found, create it and install it + // in Actor. + VMFunction *callfunc; + PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol("CallDecorateAction", false); + if (sym == NULL) + { + PSymbolVMFunction *symfunc = new PSymbolVMFunction("CallDecorateAction"); + VMNativeFunction *calldec = new VMNativeFunction(CallDecorateAction); + symfunc->Function = calldec; + sym = symfunc; + RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); + } + assert(sym->SymbolType == SYM_VMFunction); + assert(((PSymbolVMFunction *)sym)->Function != NULL); + callfunc = ((PSymbolVMFunction *)sym)->Function; + + // Create a function for this state. + VMScriptFunction *vmfunc = new VMScriptFunction; + VM_UBYTE *code = vmfunc->AllocCode(sizeof(codetemplate)/VM_OPSIZE); + memcpy(code, codetemplate, sizeof(codetemplate)); + FVoidObj *konsta = vmfunc->AllocKonstA(2); + VM_ATAG *atag = vmfunc->KonstATags(); + konsta[0].v = func->Function; + konsta[1].o = callfunc; + atag[0] = ATAG_GENERIC; + atag[1] = ATAG_OBJECT; + vmfunc->NumRegA = 4; + vmfunc->NumRegD = 1; + vmfunc->MaxParam = 6; + vmfunc->NumArgs = 5; + ActionFunc = vmfunc; + + if (setdefaultparams) ParameterIndex = func->defaultparameterindex+1; + } + else + { + ActionFunc = NULL; + if (setdefaultparams) ParameterIndex = 0; + } +} + bool FState::CallAction(AActor *self, AActor *stateowner, StateCallData *statecall) { if (ActionFunc != NULL) diff --git a/src/info.h b/src/info.h index e4e73a5f8..9ce3e662e 100644 --- a/src/info.h +++ b/src/info.h @@ -92,21 +92,7 @@ struct FState { Frame = (Frame & SF_FULLBRIGHT) | (frame-'A'); } - void SetAction(PSymbolActionFunction *func, bool setdefaultparams = true) - { -#if 0 - if (func != NULL) - { - ActionFunc = func->Function; - if (setdefaultparams) ParameterIndex = func->defaultparameterindex+1; - } - else -#endif - { - ActionFunc = NULL; - if (setdefaultparams) ParameterIndex = 0; - } - } + void SetAction(PSymbolActionFunction *func, bool setdefaultparams = true); bool CallAction(AActor *self, AActor *stateowner, StateCallData *statecall = NULL); static const PClass *StaticFindStateOwner (const FState *state); static const PClass *StaticFindStateOwner (const FState *state, const FActorInfo *info); diff --git a/src/zscript/vm.h b/src/zscript/vm.h index 61207e862..156f7787a 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -14,8 +14,10 @@ typedef unsigned short VM_UHALF; typedef signed short VM_SHALF; typedef unsigned int VM_UWORD; typedef signed int VM_SWORD; +typedef VM_UBYTE VM_ATAG; #define VM_EPSILON (1/1024.0) +#define VM_OPSIZE 4 // Number of bytes used by one opcode enum { @@ -109,7 +111,7 @@ enum class VMFunction : public DObject { - DECLARE_CLASS(VMFunction, DObject); + DECLARE_ABSTRACT_CLASS(VMFunction, DObject); public: bool Native; }; @@ -409,7 +411,7 @@ struct VMValue Type = REGT_POINTER; return *this; } - void SetPointer(void *v, VM_UBYTE atag=ATAG_GENERIC) + void SetPointer(void *v, VM_ATAG atag=ATAG_GENERIC) { Kill(); a = v; @@ -614,9 +616,9 @@ struct VMFrame return (void **)(GetRegS() + NumRegS); } - VM_UBYTE *GetRegATag() const + VM_ATAG *GetRegATag() const { - return (VM_UBYTE *)(GetRegD() + NumRegD); + return (VM_ATAG *)(GetRegD() + NumRegD); } VMValue *GetParam() const @@ -626,12 +628,12 @@ struct VMFrame void *GetExtra() const { - VM_UBYTE *ptag = GetRegATag(); - ptrdiff_t ofs = ptag - (VM_UBYTE *)this; + VM_ATAG *ptag = GetRegATag(); + ptrdiff_t ofs = ptag - (VM_ATAG *)this; return (VM_UBYTE *)this + ((ofs + NumRegA + 15) & ~15); } - void GetAllRegs(int *&d, double *&f, FString *&s, void **&a, VM_UBYTE *&atag, VMValue *¶m) const + void GetAllRegs(int *&d, double *&f, FString *&s, void **&a, VM_ATAG *&atag, VMValue *¶m) const { // Calling the individual functions produces suboptimal code. :( param = GetParam(); @@ -639,7 +641,7 @@ struct VMFrame s = (FString *)(f + NumRegF); a = (void **)(s + NumRegS); d = (int *)(a + NumRegA); - atag = (VM_UBYTE *)(d + NumRegD); + atag = (VM_ATAG *)(d + NumRegD); } void InitRegS(); @@ -660,7 +662,7 @@ struct VMRegisters double *f; FString *s; void **a; - VM_UBYTE *atag; + VM_ATAG *atag; VMValue *param; }; @@ -669,15 +671,33 @@ struct VMException : public DObject DECLARE_CLASS(VMFunction, DObject); }; +union FVoidObj +{ + DObject *o; + void *v; +}; + class VMScriptFunction : public VMFunction { DECLARE_CLASS(VMScriptFunction, VMFunction); public: - const VM_UBYTE *Code; + VMScriptFunction(); + ~VMScriptFunction(); + size_t PropagateMark(); + VM_UBYTE *AllocCode(int numops); + int *AllocKonstD(int numkonst); + double *AllocKonstF(int numkonst); + FString *AllocKonstS(int numkonst); + FVoidObj *AllocKonstA(int numkonst); + + VM_ATAG *KonstATags() { return (VM_UBYTE *)(KonstA + NumKonstA); } + const VM_ATAG *KonstATags() const { return (VM_UBYTE *)(KonstA + NumKonstA); } + + VM_UBYTE *Code; int *KonstD; double *KonstF; FString *KonstS; - void **KonstA; + FVoidObj *KonstA; int ExtraSpace; int NumCodeBytes; VM_UBYTE NumRegD; @@ -724,8 +744,13 @@ class VMNativeFunction : public VMFunction { DECLARE_CLASS(VMNativeFunction, VMFunction); public: + typedef int (*NativeCallType)(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret); + + VMNativeFunction() : NativeCall(NULL) { Native = true; } + VMNativeFunction(NativeCallType call) : NativeCall(call) { Native = true; } + // Return value is the number of results. - int (*NativeCall)(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret); + NativeCallType NativeCall; }; @@ -762,7 +787,7 @@ public: RegA++; } - void ParamPointer(void *ptr, VM_UBYTE atag) + void ParamPointer(void *ptr, VM_ATAG atag) { Reg.a[RegA] = ptr; Reg.atag[RegA] = atag; diff --git a/src/zscript/vmexec.h b/src/zscript/vmexec.h index ec41b3ac8..350845e5d 100644 --- a/src/zscript/vmexec.h +++ b/src/zscript/vmexec.h @@ -20,7 +20,8 @@ static int Exec(VMFrameStack *stack, const VM_UBYTE *pc, VMReturn *ret, int numr const int *konstd; const double *konstf; const FString *konsts; - void * const *konsta; + const FVoidObj *konsta; + const VM_ATAG *konstatag; if (f->Func != NULL && !f->Func->Native) { @@ -29,6 +30,7 @@ static int Exec(VMFrameStack *stack, const VM_UBYTE *pc, VMReturn *ret, int numr konstf = sfunc->KonstF; konsts = sfunc->KonstS; konsta = sfunc->KonstA; + konstatag = sfunc->KonstATags(); } else { @@ -37,6 +39,7 @@ static int Exec(VMFrameStack *stack, const VM_UBYTE *pc, VMReturn *ret, int numr konstf = NULL; konsts = NULL; konsta = NULL; + konstatag = NULL; } void *ptr; @@ -72,8 +75,8 @@ begin: NEXTOP; OP(LKP): ASSERTA(a); ASSERTKA(BC); - reg.a[a] = konsta[BC]; - reg.atag[a] = ATAG_OBJECT; + reg.a[a] = konsta[BC].v; + reg.atag[a] = konstatag[BC]; NEXTOP; OP(LFP): ASSERTA(a); assert(sfunc != NULL); assert(sfunc->ExtraSpace > 0); @@ -439,7 +442,7 @@ begin: break; case REGT_POINTER | REGT_KONST: assert(C < sfunc->NumKonstA); - ::new(param) VMValue(konsta[C]); + ::new(param) VMValue(konsta[C].v, konstatag[C]); break; case REGT_FLOAT: if (b & REGT_MULTIREG) @@ -486,7 +489,8 @@ begin: NEXTOP; OP(CALL_K): ASSERTKA(a); - ptr = sfunc->KonstA[a]; + assert(konstatag[a] == ATAG_OBJECT); + ptr = konsta[a].o; goto Do_CALL; OP(CALL): ASSERTA(a); @@ -572,7 +576,8 @@ begin: else { ASSERTKA(B); - throw((VMException *)konsta[B]); + assert(konstatag[B] == ATAG_OBJECT); + throw((VMException *)konsta[B].o); } NEXTOP; OP(CATCH): @@ -1224,7 +1229,7 @@ begin: NEXTOP; OP(EQA_K): ASSERTA(B); ASSERTKA(C); - CMPJMP(reg.a[B] == konsta[C]); + CMPJMP(reg.a[B] == konsta[C].v); NEXTOP; } } @@ -1254,7 +1259,8 @@ begin: { assert(pc[1] == 3); ASSERTKA(b); - type = (PClass *)konsta[b]; + assert(konstatag[b] == ATAG_OBJECT); + type = (PClass *)konsta[b].o; } ASSERTA(pc[3]); if (type == extype) @@ -1414,7 +1420,7 @@ static void FillReturns(const VMRegisters ®, VMFrame *frame, VMReturn *return static void SetReturn(const VMRegisters ®, VMFrame *frame, VMReturn *ret, VM_UBYTE regtype, int regnum) { const void *src; - VM_UBYTE atag; + VM_ATAG atag; VMScriptFunction *func = static_cast<VMScriptFunction *>(frame->Func); assert(func != NULL && !func->Native); @@ -1478,8 +1484,8 @@ static void SetReturn(const VMRegisters ®, VMFrame *frame, VMReturn *ret, VM_ if (regtype & REGT_KONST) { assert(regnum < func->NumKonstA); - ret->SetPointer(func->KonstA[regnum]); - atag = ATAG_OBJECT; + ret->SetPointer(func->KonstA[regnum].v); + atag = func->KonstATags()[regnum]; } else { diff --git a/src/zscript/vmframe.cpp b/src/zscript/vmframe.cpp index 208bc4725..80766762b 100644 --- a/src/zscript/vmframe.cpp +++ b/src/zscript/vmframe.cpp @@ -1,6 +1,95 @@ #include <new> #include "vm.h" +IMPLEMENT_CLASS(VMException) +IMPLEMENT_ABSTRACT_CLASS(VMFunction) +IMPLEMENT_CLASS(VMScriptFunction) +IMPLEMENT_CLASS(VMNativeFunction) + +VMScriptFunction::VMScriptFunction() +{ + Native = false; + Code = NULL; + KonstD = NULL; + KonstF = NULL; + KonstS = NULL; + KonstA = NULL; + ExtraSpace = 0; + NumCodeBytes = 0; + NumRegD = 0; + NumRegF = 0; + NumRegS = 0; + NumRegA = 0; + NumKonstD = 0; + NumKonstF = 0; + NumKonstS = 0; + NumKonstA = 0; + MaxParam = 0; + NumArgs = 0; +} + +VMScriptFunction::~VMScriptFunction() +{ + if (Code != NULL) M_Free(Code); + if (KonstD != NULL) M_Free(KonstD); + if (KonstF != NULL) M_Free(KonstF); + if (KonstS != NULL) delete[] KonstS; + if (KonstA != NULL) M_Free(KonstA); +} + +VM_UBYTE *VMScriptFunction::AllocCode(int numops) +{ + assert(Code == NULL && numops > 0); + numops *= VM_OPSIZE; + NumCodeBytes = numops; + return Code = (VM_UBYTE *)M_Malloc(numops); +} + +int *VMScriptFunction::AllocKonstD(int numkonst) +{ + assert(KonstD == NULL && numkonst > 0); + NumKonstD = numkonst; + return KonstD = (int *)M_Malloc(numkonst * sizeof(int)); +} + +double *VMScriptFunction::AllocKonstF(int numkonst) +{ + assert(KonstF == NULL && numkonst > 0); + NumKonstF = numkonst; + return KonstF = (double *)M_Malloc(numkonst * sizeof(double)); +} + +FString *VMScriptFunction::AllocKonstS(int numkonst) +{ + assert(KonstS == NULL && numkonst > 0); + NumKonstS = numkonst; + return KonstS = new FString[numkonst]; +} + +FVoidObj *VMScriptFunction::AllocKonstA(int numkonst) +{ + assert(KonstA == NULL && numkonst > 0); + NumKonstA = numkonst; + return KonstA = (FVoidObj *)M_Malloc(numkonst * sizeof(FVoidObj) + numkonst); +} + +size_t VMScriptFunction::PropagateMark() +{ + if (KonstA != NULL) + { + FVoidObj *konsta = KonstA; + VM_UBYTE *atag = KonstATags(); + for (int count = NumKonstA; count > 0; --count) + { + if (*atag++ == ATAG_OBJECT) + { + GC::Mark(konsta->o); + } + konsta++; + } + } + return NumKonstA * sizeof(void *) + Super::PropagateMark(); +} //=========================================================================== // From affed111fe3820c31180f2314918979701dc4835 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 25 Sep 2009 03:43:00 +0000 Subject: [PATCH 006/232] - Add THashTrait specializations for FString, double, and float. SVN r1877 (scripting) --- src/tarray.h | 15 +++++++++++++++ src/zstring.h | 8 ++++++++ 2 files changed, 23 insertions(+) diff --git a/src/tarray.h b/src/tarray.h index 92a6552e4..afea5db1e 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -398,11 +398,26 @@ template<class KT> struct THashTraits { // Returns the hash value for a key. hash_t Hash(const KT key) { return (hash_t)(intptr_t)key; } + hash_t Hash(double key) { return ((hash_t *)&key)[0] ^ ((hash_t *)&key)[1]; } // Compares two keys, returning zero if they are the same. int Compare(const KT left, const KT right) { return left != right; } }; +template<> struct THashTraits<float> +{ + // Use all bits when hashing singles instead of converting them to ints. + hash_t Hash(float key) { return *((hash_t *)&key); } + int Compare(float left, float right) { return left != right; } +}; + +template<> struct THashTraits<double> +{ + // Use all bits when hashing doubles instead of converting them to ints. + hash_t Hash(double key) { return ((hash_t *)&key)[0] ^ ((hash_t *)&key)[1]; } + int Compare(double left, double right) { return left != right; } +}; + template<class VT> struct TValueTraits { // Initializes a value for TMap. If a regular constructor isn't diff --git a/src/zstring.h b/src/zstring.h index db42b98e4..fc6287126 100644 --- a/src/zstring.h +++ b/src/zstring.h @@ -316,4 +316,12 @@ inline FName &FName::operator = (const FString &text) { Index = NameData.FindNam inline FName &FNameNoInit::operator = (const FString &text) { Index = NameData.FindName (text, text.Len(), false); return *this; } +// Hash FStrings on their contents. (used by TMap) +extern unsigned int SuperFastHash (const char *data, size_t len); +template<> struct THashTraits<FString> +{ + hash_t Hash(const FString &key) { return (hash_t)SuperFastHash(key, key.Len()); } + int Compare(const FString &left, const FString &right) { return left.Compare(right); } +}; + #endif From e9db2c83a5e8fb9845cbb795ca8f562815cd9ec0 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 25 Sep 2009 03:44:58 +0000 Subject: [PATCH 007/232] - Just some stuff. SVN r1878 (scripting) --- src/CMakeLists.txt | 1 + src/zscript/vmbuilder.cpp | 413 ++++++++++++++++++++++++++++++++++++++ src/zscript/vmbuilder.h | 77 +++++++ zdoom.vcproj | 8 + 4 files changed, 499 insertions(+) create mode 100644 src/zscript/vmbuilder.cpp create mode 100644 src/zscript/vmbuilder.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 91e187574..50da166d9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -770,6 +770,7 @@ add_executable( zdoom WIN32 timidity/resample.cpp timidity/timidity.cpp xlat/parse_xlat.cpp + zscript/vmbuilder.cpp zscript/vmdisasm.cpp zscript/vmexec.cpp zscript/vmframe.cpp diff --git a/src/zscript/vmbuilder.cpp b/src/zscript/vmbuilder.cpp new file mode 100644 index 000000000..d700b9908 --- /dev/null +++ b/src/zscript/vmbuilder.cpp @@ -0,0 +1,413 @@ +#include "vmbuilder.h" + +//========================================================================== +// +// VMFunctionBuilder - Constructor +// +//========================================================================== + +VMFunctionBuilder::VMFunctionBuilder() +{ + NumIntConstants = 0; + NumFloatConstants = 0; + NumAddressConstants = 0; + NumStringConstants = 0; + MaxParam = 0; + ActiveParam = 0; +} + +//========================================================================== +// +// VMFunctionBuilder - Destructor +// +//========================================================================== + +VMFunctionBuilder::~VMFunctionBuilder() +{ +} + +//========================================================================== +// +// VMFunctionBuilder :: MakeFunction +// +// Creates a new VMScriptFunction out of the data passed to this class. +// +//========================================================================== + +VMScriptFunction *VMFunctionBuilder::MakeFunction() +{ + VMScriptFunction *func = new VMScriptFunction; + + // Copy code block. + memcpy(func->AllocCode(Code.Size()), &Code[0], Code.Size()); + + // Create constant tables. + if (NumIntConstants > 0) + { + FillIntConstants(func->AllocKonstD(NumIntConstants)); + } + if (NumFloatConstants > 0) + { + FillFloatConstants(func->AllocKonstF(NumFloatConstants)); + } + if (NumAddressConstants > 0) + { + func->AllocKonstA(NumAddressConstants); + FillAddressConstants(func->KonstA, func->KonstATags()); + } + if (NumStringConstants > 0) + { + FillStringConstants(func->AllocKonstS(NumStringConstants)); + } + + // Assign required register space. + func->NumRegD = IntRegisters.MostUsed; + func->NumRegF = FloatRegisters.MostUsed; + func->NumRegA = AddressRegisters.MostUsed; + func->NumRegS = StringRegisters.MostUsed; + func->MaxParam = MaxParam; + + // Technically, there's no reason why we can't end the function with + // entries on the parameter stack, but it means the caller probably + // did something wrong. + assert(ActiveParam == 0); + + return func; +} + +//========================================================================== +// +// VMFunctionBuilder :: FillIntConstants +// +//========================================================================== + +void VMFunctionBuilder::FillIntConstants(int *konst) +{ + TMapIterator<int, int> it(IntConstants); + TMap<int, int>::Pair *pair; + + while (it.NextPair(pair)) + { + konst[pair->Value] = pair->Key; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: FillFloatConstants +// +//========================================================================== + +void VMFunctionBuilder::FillFloatConstants(double *konst) +{ + TMapIterator<double, int> it(FloatConstants); + TMap<double, int>::Pair *pair; + + while (it.NextPair(pair)) + { + konst[pair->Value] = pair->Key; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: FillAddressConstants +// +//========================================================================== + +void VMFunctionBuilder::FillAddressConstants(FVoidObj *konst, VM_ATAG *tags) +{ + TMapIterator<void *, AddrKonst> it(AddressConstants); + TMap<void *, AddrKonst>::Pair *pair; + + while (it.NextPair(pair)) + { + konst[pair->Value.KonstNum].v = pair->Key; + tags[pair->Value.KonstNum] = pair->Value.Tag; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: FillStringConstants +// +//========================================================================== + +void VMFunctionBuilder::FillStringConstants(FString *konst) +{ + TMapIterator<FString, int> it(StringConstants); + TMap<FString, int>::Pair *pair; + + while (it.NextPair(pair)) + { + konst[pair->Value] = pair->Key; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: GetConstantInt +// +// Returns a constant register initialized with the given value, or -1 if +// there were no more constants free. +// +//========================================================================== + +int VMFunctionBuilder::GetConstantInt(int val) +{ + int *locp = IntConstants.CheckKey(val); + if (locp != NULL) + { + return *locp; + } + else + { + int loc = NumIntConstants++; + IntConstants.Insert(val, loc); + return loc; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: GetConstantFloat +// +// Returns a constant register initialized with the given value, or -1 if +// there were no more constants free. +// +//========================================================================== + +int VMFunctionBuilder::GetConstantFloat(double val) +{ + int *locp = FloatConstants.CheckKey(val); + if (locp != NULL) + { + return *locp; + } + else + { + int loc = NumFloatConstants++; + FloatConstants.Insert(val, loc); + return loc; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: GetConstantString +// +// Returns a constant register initialized with the given value, or -1 if +// there were no more constants free. +// +//========================================================================== + +int VMFunctionBuilder::GetConstantString(FString val) +{ + int *locp = StringConstants.CheckKey(val); + if (locp != NULL) + { + return *locp; + } + else + { + int loc = NumStringConstants++; + StringConstants.Insert(val, loc); + return loc; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: GetConstantAddress +// +// Returns a constant register initialized with the given value, or -1 if +// there were no more constants free. +// +//========================================================================== + +int VMFunctionBuilder::GetConstantAddress(void *ptr, VM_ATAG tag) +{ + AddrKonst *locp = AddressConstants.CheckKey(ptr); + if (locp != NULL) + { + // There should only be one tag associated with a memory location. + assert(locp->Tag == tag); + return locp->KonstNum; + } + else + { + AddrKonst loc = { NumAddressConstants++, tag }; + AddressConstants.Insert(ptr, loc); + return loc.KonstNum; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: ParamChange +// +// Adds delta to ActiveParam and keeps track of MaxParam. +// +//========================================================================== + +void VMFunctionBuilder::ParamChange(int delta) +{ + assert(delta > 0 || -delta <= ActiveParam); + ActiveParam += delta; + if (ActiveParam > MaxParam) + { + MaxParam = ActiveParam; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: RegAvailability - Constructor +// +//========================================================================== + +VMFunctionBuilder::RegAvailability::RegAvailability() +{ + memset(Used, 0, sizeof(Used)); + MostUsed = 0; +} + +//========================================================================== +// +// VMFunctionBuilder :: RegAvailibity :: GetReg +// +// Gets one or more unused registers. If getting multiple registers, they +// will all be consecutive. Returns -1 if there were not enough consecutive +// registers to satisfy the request. +// +// Preference is given to low-numbered registers in an attempt to keep +// the maximum register count low so as to preserve VM stack space when this +// function is executed. +// +//========================================================================== + +int VMFunctionBuilder::RegAvailability::GetReg(int count) +{ + VM_UWORD mask; + int i, firstbit; + + // Getting fewer than one register makes no sense, and + // the algorithm used here can only obtain ranges of up to 32 bits. + if (count < 1 || count > 32) + { + return -1; + } + + mask = count == 32 ? ~0u : (1 << count) - 1; + + for (i = 0; i < 256/32; ++i) + { + // Find the first word with free registers + VM_UWORD bits = Used[i]; + if (bits != ~0u) + { + // Are there enough consecutive bits to satisfy the request? + // Search by 16, then 8, then 1 bit at a time for the first + // free register. + if ((bits & 0xFFFF) == 0xFFFF) + { + firstbit = ((bits & 0xFF0000) == 0xFF0000) ? 24 : 16; + } + else + { + firstbit = ((bits & 0xFF) == 0xFF) ? 8 : 0; + } + for (; firstbit < 32; ++firstbit) + { + if (((bits >> firstbit) & mask) == 0) + { + if (firstbit + count <= 32) + { // Needed bits all fit in one word, so we got it. + if (firstbit + count > MostUsed) + { + MostUsed = firstbit + count; + } + Used[i] |= mask << firstbit; + return i * 32 + firstbit; + } + // Needed bits span two words, so check the next word. + else if (i < 256/32 - 1) + { // There is a next word. + if (((Used[i + 1]) & (mask >> (32 - firstbit))) == 0) + { // The next word has the needed open space, too. + if (firstbit + count > MostUsed) + { + MostUsed = firstbit + count; + } + Used[i] |= mask << firstbit; + Used[i + 1] |= mask >> (32 - firstbit); + return i * 32 + firstbit; + } + else + { // Skip to the next word, because we know we won't find + // what we need if we stay inside this one. All bits + // from firstbit to the end of the word are 0. If the + // next word does not start with the x amount of 0's, we + // need to satisfy the request, then it certainly won't + // have the x+1 0's we would need if we started at + // firstbit+1 in this one. + firstbit = 32; + } + } + else + { // Out of words. + break; + } + } + } + } + } + // No room! + return -1; +} + +//========================================================================== +// +// VMFunctionBuilder :: RegAvailibity :: ReturnReg +// +// Marks a range of registers as free again. +// +//========================================================================== + +void VMFunctionBuilder::RegAvailability::ReturnReg(int reg, int count) +{ + assert(count >= 1 && count <= 32); + assert(reg >= 0 && reg + count <= 256); + + VM_UWORD mask, partialmask; + int firstword, firstbit; + + mask = count == 32 ? ~0u : (1 << count) - 1; + firstword = reg / 32; + firstbit = reg & 31; + + if (firstbit + count <= 32) + { // Range is all in one word. + mask <<= firstbit; + // If we are trying to return registers that are already free, + // it probably means that the caller messed up somewhere. + assert((Used[firstword] & mask) == mask); + Used[firstword] &= ~mask; + } + else + { // Range is in two words. + partialmask = mask << firstbit; + assert((Used[firstword] & partialmask) == partialmask); + Used[firstword] &= ~partialmask; + + partialmask = mask >> (32 - firstbit); + assert((Used[firstword + 1] & partialmask) == partialmask); + Used[firstword + 1] &= ~partialmask; + } +} + +void VMFunctionBuilder::RegAvailability::Dump() +{ + Printf("%032B %032B %032B %032B\n%032B %032B %032B %032B\n", + Used[0], Used[1], Used[2], Used[3], Used[4], Used[5], Used[6], Used[7]); +} diff --git a/src/zscript/vmbuilder.h b/src/zscript/vmbuilder.h new file mode 100644 index 000000000..95d6f9dd3 --- /dev/null +++ b/src/zscript/vmbuilder.h @@ -0,0 +1,77 @@ +#ifndef VMUTIL_H +#define VMUTIL_H + +#include "vm.h" + +class VMFunctionBuilder +{ +public: + // Keeps track of which registers are available by way of a bitmask table. + class RegAvailability + { + public: + RegAvailability(); + int GetReg(int count); // Returns the first register in the range + void ReturnReg(int reg, int count); + void Dump(); + + private: + VM_UWORD Used[256/32]; // Bitmap of used registers (bit set means reg is used) + int MostUsed; + + friend class VMFunctionBuilder; + }; + + VMFunctionBuilder(); + ~VMFunctionBuilder(); + + VMScriptFunction *MakeFunction(); + + // Returns the constant register holding the value. + int GetConstantInt(int val); + int GetConstantFloat(double val); + int GetConstantAddress(void *ptr, VM_ATAG tag); + int GetConstantString(FString str); + + // Returns the address of the newly-emitted instruction. + size_t Emit(int opcode, int opa, int opb, int opc); + + // Write out complete constant tables. + void FillIntConstants(int *konst); + void FillFloatConstants(double *konst); + void FillAddressConstants(FVoidObj *konst, VM_ATAG *tags); + void FillStringConstants(FString *strings); + + // PARAM increases ActiveParam; CALL decreases it. + void ParamChange(int delta); + + // Track available registers. + RegAvailability IntRegisters; + RegAvailability FloatRegisters; + RegAvailability AddressRegisters; + RegAvailability StringRegisters; + +private: + struct AddrKonst + { + int KonstNum; + VM_ATAG Tag; + }; + // These map from the constant value to its position in the constant table. + TMap<int, int> IntConstants; + TMap<double, int> FloatConstants; + TMap<void *, AddrKonst> AddressConstants; + TMap<FString, int> StringConstants; + + int NumIntConstants; + int NumFloatConstants; + int NumAddressConstants; + int NumStringConstants; + + int MaxParam; + int ActiveParam; + + TArray<VM_UBYTE> Code; +}; + +#endif diff --git a/zdoom.vcproj b/zdoom.vcproj index cbe559734..9e7256cb3 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -6449,6 +6449,14 @@ RelativePath=".\src\zscript\vm.h" > </File> + <File + RelativePath=".\src\zscript\vmbuilder.cpp" + > + </File> + <File + RelativePath=".\src\zscript\vmbuilder.h" + > + </File> <File RelativePath=".\src\zscript\vmdisasm.cpp" > From 3001708d16250df77dd781ecaffbd09c8a48662c Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sun, 11 Oct 2009 00:02:14 +0000 Subject: [PATCH 008/232] - Added some code for generating VM code from FxExpressions. This is completely untested, since it isn't even used anywhere yet. In retrospect, I probably should have targeted an intermediate representation and done codegen with that instead, since that would be something I can reuse. SVN r1908 (scripting) --- src/thingdef/thingdef_exp.h | 62 ++ src/thingdef/thingdef_expression.cpp | 1235 +++++++++++++++++++++++++- src/zscript/vm.h | 1 + src/zscript/vmbuilder.cpp | 122 ++- src/zscript/vmbuilder.h | 19 +- src/zscript/vmexec.cpp | 9 +- src/zscript/vmexec.h | 7 + src/zscript/vmops.h | 5 +- 8 files changed, 1430 insertions(+), 30 deletions(-) diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 5ef7b9bcc..d75000d41 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -42,12 +42,14 @@ #include "m_random.h" + #define CHECKRESOLVED() if (isresolved) return this; isresolved=true; #define SAFE_DELETE(p) if (p!=NULL) { delete p; p=NULL; } #define RESOLVE(p,c) if (p!=NULL) p = p->Resolve(c) #define ABORT(p) if (!(p)) { delete this; return NULL; } #define SAFE_RESOLVE(p,c) RESOLVE(p,c); ABORT(p) +class VMFunctionBuilder; extern PSymbolTable GlobalSymbols; //========================================================================== @@ -142,6 +144,15 @@ struct ExpVal }; +struct ExpEmit +{ + ExpEmit() : RegNum(0), RegType(REGT_NIL) {} + ExpEmit(int reg, int type) : RegNum(reg), RegType(type) {} + ExpEmit(int reg, int type, bool konst) : RegNum(reg), RegType(type), Konst(konst) {} + ExpEmit(VMFunctionBuilder *build, int type); + + BYTE RegNum, RegType, Konst; +}; //========================================================================== // @@ -166,12 +177,25 @@ public: virtual bool isConstant() const; virtual void RequestAddress(); + virtual ExpEmit Emit(VMFunctionBuilder *build); + FScriptPosition ScriptPosition; FExpressionType ValueType; bool isresolved; }; +class FxParameter : public FxExpression +{ + FxExpression *Operand; + +public: + FxParameter(FxExpression*); + ~FxParameter(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxIdentifier @@ -310,6 +334,21 @@ public: FxExpression *Resolve(FCompileContext&); ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); +}; + +class FxFloatCast : public FxExpression +{ + FxExpression *basex; + +public: + + FxFloatCast(FxExpression *x); + ~FxFloatCast(); + FxExpression *Resolve(FCompileContext&); + + ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; @@ -327,6 +366,7 @@ public: FxPlusSign(FxExpression*); ~FxPlusSign(); FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -344,6 +384,7 @@ public: ~FxMinusSign(); FxExpression *Resolve(FCompileContext&); ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -361,6 +402,7 @@ public: ~FxUnaryNotBitwise(); FxExpression *Resolve(FCompileContext&); ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -378,6 +420,7 @@ public: ~FxUnaryNotBoolean(); FxExpression *Resolve(FCompileContext&); ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -396,6 +439,7 @@ public: FxBinary(int, FxExpression*, FxExpression*); ~FxBinary(); bool ResolveLR(FCompileContext& ctx, bool castnumeric); + void Promote(); }; //========================================================================== @@ -411,6 +455,7 @@ public: FxAddSub(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -426,6 +471,7 @@ public: FxMulDiv(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -441,6 +487,7 @@ public: FxCompareRel(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -456,6 +503,7 @@ public: FxCompareEq(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -471,6 +519,7 @@ public: FxBinaryInt(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -491,6 +540,7 @@ public: FxExpression *Resolve(FCompileContext&); ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -511,6 +561,7 @@ public: FxExpression *Resolve(FCompileContext&); ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -530,6 +581,7 @@ public: FxExpression *Resolve(FCompileContext&); ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -551,6 +603,7 @@ public: FxExpression *Resolve(FCompileContext&); ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -564,6 +617,7 @@ class FxFRandom : public FxRandom public: FxFRandom(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos); ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -584,6 +638,7 @@ public: FxExpression *Resolve(FCompileContext&); ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; @@ -623,6 +678,7 @@ public: FxExpression *Resolve(FCompileContext&); void RequestAddress(); ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -637,6 +693,7 @@ public: FxSelf(const FScriptPosition&); FxExpression *Resolve(FCompileContext&); ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -657,6 +714,7 @@ public: FxExpression *Resolve(FCompileContext&); //void RequestAddress(); ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; @@ -700,6 +758,7 @@ public: ~FxActionSpecialCall(); FxExpression *Resolve(FCompileContext&); ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -719,6 +778,7 @@ public: ~FxGlobalFunctionCall(); FxExpression *Resolve(FCompileContext&); ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; @@ -739,6 +799,7 @@ public: ~FxClassTypeCast(); FxExpression *Resolve(FCompileContext&); ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -775,6 +836,7 @@ public: FxMultiNameState(const char *statestring, const FScriptPosition &pos); FxExpression *Resolve(FCompileContext&); ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 60a01586b..eb02a1892 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -49,6 +49,7 @@ #include "p_lnspec.h" #include "doomstat.h" #include "thingdef_exp.h" +#include "vmbuilder.h" // Accessible actor member variables DEFINE_MEMBER_VARIABLE(alpha, AActor) @@ -77,6 +78,11 @@ DEFINE_MEMBER_VARIABLE(Damage, AActor) DEFINE_MEMBER_VARIABLE(Score, AActor) DEFINE_MEMBER_VARIABLE(uservar, AActor) +ExpEmit::ExpEmit(VMFunctionBuilder *build, int type) +: RegNum(build->Registers[type].Get(1)), RegType(type) +{ +} + //========================================================================== // // EvalExpression @@ -244,6 +250,18 @@ ExpVal FxExpression::EvalExpression (AActor *self) return val; } +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxExpression::Emit (VMFunctionBuilder *build) +{ + ScriptPosition.Message(MSG_ERROR, "Unemitted expression found"); + return ExpEmit(); +} + //========================================================================== // @@ -306,6 +324,80 @@ void FxExpression::RequestAddress() ScriptPosition.Message(MSG_ERROR, "invalid dereference\n"); } +//========================================================================== +// +// +// +//========================================================================== + +FxParameter::FxParameter(FxExpression *operand) +: FxExpression(operand->ScriptPosition) +{ + Operand = operand; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxParameter::~FxParameter() +{ + SAFE_DELETE(Operand); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxParameter::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Operand, ctx); + return this; +} + +ExpEmit FxParameter::Emit(VMFunctionBuilder *build) +{ + if (Operand->isConstant()) + { + ExpVal val = Operand->EvalExpression(NULL); + if (val.Type == VAL_Int || val.Type == VAL_Sound || val.Type == VAL_Name || val.Type == VAL_Color) + { + build->Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, build->GetConstantInt(val.Int)); + } + else if (val.Type == VAL_Float) + { + build->Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, build->GetConstantFloat(val.Int)); + } + else if (val.Type == VAL_Class || val.Type == VAL_Object) + { + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(val.pointer, ATAG_OBJECT)); + } + else if (val.Type == VAL_State) + { + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(val.pointer, ATAG_STATE)); + } + else + { + ScriptPosition.Message(MSG_ERROR, "Cannot emit needed constant"); + } + } + else + { + ExpEmit where = Operand->Emit(build); + + if (where.RegNum == REGT_NIL) + { + ScriptPosition.Message(MSG_ERROR, "Attempted to pass a non-value"); + build->Emit(OP_PARAM, 0, where.RegType, where.RegNum); + } + } + return ExpEmit(); +} //========================================================================== // @@ -353,8 +445,6 @@ FxExpression *FxConstant::MakeConstant(PSymbol *sym, const FScriptPosition &pos) return x; } - - //========================================================================== // // @@ -430,6 +520,100 @@ ExpVal FxIntCast::EvalExpression (AActor *self) return baseval; } +ExpEmit FxIntCast::Emit(VMFunctionBuilder *build) +{ + ExpEmit from = basex->Emit(build); + assert(!from.Konst); + assert(basex->ValueType == VAL_Float); + ExpEmit to(build, REGT_INT); + build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_F2I); + return to; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxFloatCast::FxFloatCast(FxExpression *x) +: FxExpression(x->ScriptPosition) +{ + basex=x; + ValueType = VAL_Float; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxFloatCast::~FxFloatCast() +{ + SAFE_DELETE(basex); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxFloatCast::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(basex, ctx); + + if (basex->ValueType == VAL_Float) + { + FxExpression *x = basex; + basex = NULL; + delete this; + return x; + } + else if (basex->ValueType == VAL_Int) + { + if (basex->isConstant()) + { + ExpVal constval = basex->EvalExpression(NULL); + FxExpression *x = new FxConstant(constval.GetFloat(), ScriptPosition); + delete this; + return x; + } + return this; + } + else + { + ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); + delete this; + return NULL; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpVal FxFloatCast::EvalExpression (AActor *self) +{ + ExpVal baseval = basex->EvalExpression(self); + baseval.Float = baseval.GetFloat(); + baseval.Type = VAL_Float; + return baseval; +} + +ExpEmit FxFloatCast::Emit(VMFunctionBuilder *build) +{ + ExpEmit from = basex->Emit(build); + assert(!from.Konst); + assert(basex->ValueType == VAL_Int); + ExpEmit to(build, REGT_FLOAT); + build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_I2F); + return to; +} //========================================================================== // @@ -480,6 +664,11 @@ FxExpression *FxPlusSign::Resolve(FCompileContext& ctx) } } +ExpEmit FxPlusSign::Emit(VMFunctionBuilder *build) +{ + return Operand->Emit(build); +} + //========================================================================== // // @@ -559,6 +748,23 @@ ExpVal FxMinusSign::EvalExpression (AActor *self) return ret; } +ExpEmit FxMinusSign::Emit(VMFunctionBuilder *build) +{ + assert(ValueType.Type == Operand->ValueType.Type); + ExpEmit from = Operand->Emit(build); + assert(from.Konst != 0); + // Do it in-place. + if (ValueType == VAL_Int) + { + build->Emit(OP_NEG, from.RegNum, from.RegNum, 0); + } + else + { + assert(ValueType == VAL_Float); + build->Emit(OP_NEG, from.RegNum, from.RegNum, 0); + } + return from; +} //========================================================================== // @@ -639,6 +845,17 @@ ExpVal FxUnaryNotBitwise::EvalExpression (AActor *self) return ret; } +ExpEmit FxUnaryNotBitwise::Emit(VMFunctionBuilder *build) +{ + assert(ValueType.Type == Operand->ValueType.Type); + assert(ValueType == VAL_Int); + ExpEmit from = Operand->Emit(build); + assert(from.Konst != 0); + // Do it in-place. + build->Emit(OP_NOT, from.RegNum, from.RegNum, 0); + return from; +} + //========================================================================== // // @@ -716,6 +933,36 @@ ExpVal FxUnaryNotBoolean::EvalExpression (AActor *self) return ret; } +ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build) +{ + ExpEmit from = Operand->Emit(build); + assert(from.Konst != 0); + ExpEmit to(build, REGT_INT); + build->FreeReg(from.RegType, from.RegNum); + + // Preload result with 0. + build->Emit(OP_LI, to.RegNum, 0, 0); + + // Check source against 0. + if (from.RegType == REGT_INT) + { + build->Emit(OP_EQ_R, 0, from.RegNum, to.RegNum); + } + else if (from.RegType == REGT_FLOAT) + { + build->Emit(OP_EQF_K, 0, from.RegNum, build->GetConstantFloat(0)); + } + else if (from.RegNum == REGT_POINTER) + { + build->Emit(OP_EQA_K, 0, from.RegNum, build->GetConstantAddress(NULL, ATAG_GENERIC)); + } + build->Emit(OP_JMP, 1); + + // Reload result with 1 if the comparison fell through. + build->Emit(OP_LI, to.RegNum, 1); + return to; +} + //========================================================================== // // @@ -786,6 +1033,17 @@ bool FxBinary::ResolveLR(FCompileContext& ctx, bool castnumeric) return true; } +void FxBinary::Promote() +{ + if (left->ValueType == VAL_Float && right->ValueType == VAL_Int) + { + right = new FxFloatCast(right); + } + else if (left->ValueType == VAL_Int && right->ValueType == VAL_Float) + { + left = new FxFloatCast(left); + } +} //========================================================================== // @@ -845,6 +1103,7 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx) } } + Promote(); return this; } @@ -880,6 +1139,72 @@ ExpVal FxAddSub::EvalExpression (AActor *self) return ret; } +ExpEmit FxAddSub::Emit(VMFunctionBuilder *build) +{ + assert(Operator == '+' || Operator == '-'); + ExpEmit op1 = left->Emit(build); + ExpEmit op2 = right->Emit(build); + if (Operator == '+') + { + // Since addition is commutative, only the second operand may be a constant. + if (op1.Konst) + { + swap(op1, op2); + } + assert(!op1.Konst); + build->FreeReg(op1.RegType, op1.RegNum); + if (!op2.Konst) + { + build->FreeReg(op2.RegType, op2.RegNum); + } + if (ValueType == VAL_Float) + { + assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); + ExpEmit to(build, REGT_FLOAT); + build->Emit(op2.Konst ? OP_ADDF_RK : OP_ADDF_RR, to.RegNum, op1.RegNum, op2.RegNum); + return to; + } + else + { + assert(ValueType == VAL_Int); + assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT); + ExpEmit to(build, REGT_INT); + build->Emit(op2.Konst ? OP_ADD_RK : OP_ADD_RR, to.RegNum, op1.RegNum, op2.RegNum); + return to; + } + } + else + { + // Subtraction is not commutative, so either side may be constant (but not both). + assert(!op1.Konst || !op2.Konst); + if (!op1.Konst) + { + build->FreeReg(op1.RegType, op1.RegNum); + } + if (!op2.Konst) + { + build->FreeReg(op2.RegType, op2.RegNum); + } + if (ValueType == VAL_Float) + { + assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); + ExpEmit to(build, REGT_FLOAT); + build->Emit(op1.Konst ? OP_SUBF_KR : op2.Konst ? OP_SUBF_RK : OP_SUBF_RR, + to.RegNum, op1.RegNum, op2.RegNum); + return to; + } + else + { + assert(ValueType == VAL_Int); + assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT); + ExpEmit to(build, REGT_INT); + build->Emit(op1.Konst ? OP_SUB_KR : op2.Konst ? OP_SUB_RK : OP_SUB_RR, + to.RegNum, op1.RegNum, op2.RegNum); + return to; + } + } +} + //========================================================================== // // @@ -955,6 +1280,7 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) } } + Promote(); return this; } @@ -1003,6 +1329,74 @@ ExpVal FxMulDiv::EvalExpression (AActor *self) return ret; } +ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build) +{ + ExpEmit op1 = left->Emit(build); + ExpEmit op2 = right->Emit(build); + + if (Operator == '*') + { + // Multiplication is commutative, so only the second operand may be constant. + if (op1.Konst) + { + swap(op1, op2); + } + assert(!op1.Konst); + if (!op2.Konst) + { + build->FreeReg(op2.RegType, op2.RegNum); + } + if (ValueType == VAL_Float) + { + assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); + ExpEmit to(build, REGT_FLOAT); + build->Emit(op2.Konst ? OP_MULF_RK : OP_MULF_RR, to.RegNum, op1.RegNum, op2.RegNum); + return to; + } + else + { + assert(ValueType == VAL_Int); + assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT); + ExpEmit to(build, REGT_INT); + build->Emit(op2.Konst ? OP_MUL_RK : OP_MUL_RR, to.RegNum, op1.RegNum, op2.RegNum); + return to; + } + } + else + { + // Division is not commutative, so either side may be constant (but not both). + assert(!op1.Konst || !op2.Konst); + assert(Operator == '%' || Operator == '/'); + if (!op1.Konst) + { + build->FreeReg(op1.RegType, op1.RegNum); + } + if (!op2.Konst) + { + build->FreeReg(op2.RegType, op2.RegNum); + } + if (ValueType == VAL_Float) + { + assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); + ExpEmit to(build, REGT_FLOAT); + build->Emit(Operator == '/' ? (op1.Konst ? OP_DIVF_KR : op2.Konst ? OP_DIVF_RK : OP_DIVF_RR) + : (op1.Konst ? OP_MODF_KR : op2.Konst ? OP_MODF_RK : OP_MODF_RR), + to.RegNum, op1.RegNum, op2.RegNum); + return to; + } + else + { + assert(ValueType == VAL_Int); + assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT); + ExpEmit to(build, REGT_INT); + build->Emit(Operator == '/' ? (op1.Konst ? OP_DIV_KR : op2.Konst ? OP_DIV_RK : OP_DIV_RR) + : (op1.Konst ? OP_MOD_KR : op2.Konst ? OP_MOD_RK : OP_MOD_RR), + to.RegNum, op1.RegNum, op2.RegNum); + return to; + } + } +} + //========================================================================== // // @@ -1057,6 +1451,7 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) delete this; return e; } + Promote(); ValueType = VAL_Int; return this; } @@ -1095,6 +1490,53 @@ ExpVal FxCompareRel::EvalExpression (AActor *self) return ret; } +ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build) +{ + ExpEmit op1 = left->Emit(build); + ExpEmit op2 = right->Emit(build); + assert(op1.RegType == op2.RegType); + assert(op1.RegType == REGT_INT || op1.RegType == REGT_FLOAT); + assert(!op1.Konst || !op2.Konst); + assert(Operator == '<' || Operator == '>' || Operator == TK_Geq || Operator == TK_Leq); + static const VM_UBYTE InstrMap[][4] = + { + { OP_LT_RR, OP_LTF_RR, 0 }, // < + { OP_LE_RR, OP_LEF_RR, 1 }, // > + { OP_LT_RR, OP_LTF_RR, 1 }, // >= + { OP_LE_RR, OP_LE_RR, 0 } // <= + }; + int instr, check, index; + + index = Operator == '<' ? 0 : + Operator == '>' ? 1 : + Operator == TK_Geq ? 2 : 3; + instr = InstrMap[index][op1.RegType == REGT_INT ? 0 : 1]; + check = InstrMap[index][2]; + if (op2.Konst) + { + instr += 1; + } + else + { + build->FreeReg(op2.RegType, op2.RegNum); + } + if (op1.Konst) + { + instr += 2; + } + else + { + build->FreeReg(op1.RegType, op1.RegNum); + } + ExpEmit to(build, op1.RegType); + + // See FxUnaryNotBoolean for comments, since it's the same thing. + build->Emit(OP_LI, to.RegNum, 0, 0); + build->Emit(instr, check, op1.RegNum, op2.RegNum); + build->Emit(OP_JMP, 1); + build->Emit(OP_LI, to.RegNum, 1); + return to; +} //========================================================================== // @@ -1162,6 +1604,7 @@ cont: delete this; return e; } + Promote(); ValueType = VAL_Int; return this; } @@ -1184,7 +1627,7 @@ ExpVal FxCompareEq::EvalExpression (AActor *self) double v2 = right->EvalExpression(self).GetFloat(); ret.Int = Operator == TK_Eq? v1 == v2 : v1 != v2; } - else if (ValueType == VAL_Int) + else if (left->ValueType == VAL_Int) { int v1 = left->EvalExpression(self).GetInt(); int v2 = right->EvalExpression(self).GetInt(); @@ -1198,6 +1641,42 @@ ExpVal FxCompareEq::EvalExpression (AActor *self) return ret; } +ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build) +{ + ExpEmit op1 = left->Emit(build); + ExpEmit op2 = right->Emit(build); + assert(op1.RegType == op2.RegType); + assert(op1.RegType == REGT_INT || op1.RegType == REGT_FLOAT || op1.RegType == REGT_POINTER); + int instr; + + // Only the second operand may be constant. + if (op1.Konst) + { + swap(op1, op2); + } + assert(!op1.Konst); + + instr = op1.RegType == REGT_INT ? OP_EQ_R : + op1.RegType == REGT_FLOAT ? OP_EQF_R : + OP_EQA_R; + build->FreeReg(op1.RegType, op1.RegNum); + if (!op2.Konst) + { + build->FreeReg(op2.RegType, op2.RegNum); + } + else + { + instr += 1; + } + ExpEmit to(build, op1.RegType); + + // See FxUnaryNotBoolean for comments, since it's the same thing. + build->Emit(OP_LI, to.RegNum, 0, 0); + build->Emit(instr, Operator != TK_Eq, op1.RegNum, op2.RegNum); + build->Emit(OP_JMP, 1); + build->Emit(OP_LI, to.RegNum, 1); + return to; +} //========================================================================== // @@ -1293,6 +1772,82 @@ ExpVal FxBinaryInt::EvalExpression (AActor *self) return ret; } +ExpEmit FxBinaryInt::Emit(VMFunctionBuilder *build) +{ + assert(left->ValueType == VAL_Int); + assert(right->ValueType == VAL_Int); + static const VM_UBYTE InstrMap[][4] = + { + { OP_SLL_RR, OP_SLL_KR, OP_SLL_RI }, // TK_LShift + { OP_SRA_RR, OP_SRA_KR, OP_SRA_RI }, // TK_RShift + { OP_SRL_RR, OP_SRL_KR, OP_SRL_RI }, // TK_URShift + { OP_AND_RR, 0, OP_AND_RK }, // '&' + { OP_OR_RR, 0, OP_OR_RK }, // '|' + { OP_XOR_RR, 0, OP_XOR_RK }, // '^' + }; + int index, instr, rop; + ExpEmit op1, op2; + + index = Operator == TK_LShift ? 0 : + Operator == TK_RShift ? 1 : + Operator == TK_URShift ? 2 : + Operator == '&' ? 3 : + Operator == '|' ? 4 : + Operator == '^' ? 5 : -1; + assert(index >= 0); + op1 = left->Emit(build); + if (index < 3) + { // Shift instructions use right-hand immediates instead of constant registers. + if (right->isConstant()) + { + rop = right->EvalExpression(NULL).GetInt(); + op2.Konst = true; + } + else + { + op2 = right->Emit(build); + assert(!op2.Konst); + build->FreeReg(op2.RegType, op2.RegNum); + rop = op2.RegNum; + } + } + else + { // The other operators only take a constant on the right-hand side. + op2 = right->Emit(build); + if (op1.Konst) + { + swap(op1, op2); + } + assert(!op1.Konst); + rop = op2.RegNum; + if (!op2.Konst) + { + build->FreeReg(op2.RegType, op2.RegNum); + } + } + if (!op1.Konst) + { + build->FreeReg(op1.RegType, op1.RegNum); + if (!op2.Konst) + { + instr = InstrMap[index][0]; + } + else + { + instr = InstrMap[index][2]; + } + } + else + { + assert(!op2.Konst); + instr = InstrMap[index][1]; + } + assert(instr != 0); + ExpEmit to(build, REGT_INT); + build->Emit(instr, to.RegNum, op1.RegNum, rop); + return to; +} + //========================================================================== // // @@ -1402,6 +1957,14 @@ FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx) return x; } } + if (left->ValueType != VAL_Int && left->ValueType != VAL_Sound) + { + left = new FxIntCast(left); + } + if (right->ValueType != VAL_Int && right->ValueType != VAL_Sound) + { + right = new FxIntCast(right); + } return this; } @@ -1430,6 +1993,59 @@ ExpVal FxBinaryLogical::EvalExpression (AActor *self) return ret; } +ExpEmit FxBinaryLogical::Emit(VMFunctionBuilder *build) +{ + // This is not the "right" way to do these, but it works for now. + // (Problem: No information sharing is done between nodes to reduce the + // code size if you have something like a1 && a2 && a3 && ... && an.) + assert(left->ValueType == VAL_Int && right->ValueType == VAL_Int); + ExpEmit op1 = left->Emit(build); + assert(!op1.Konst); + int zero = build->GetConstantInt(0); + build->FreeReg(op1.RegType, op1.RegNum); + + if (Operator == TK_AndAnd) + { + build->Emit(OP_EQ_K, 1, op1.RegNum, zero); + // If op1 is 0, skip evaluation of op2. + size_t patchspot = build->Emit(OP_JMP, 0, 0, 0); + + // Evaluate op2. + ExpEmit op2 = right->Emit(build); + assert(!op2.Konst); + build->FreeReg(op2.RegType, op2.RegNum); + + ExpEmit to(build, REGT_INT); + build->Emit(OP_EQ_K, 0, op2.RegNum, zero); + build->Emit(OP_JMP, 2); + build->Emit(OP_LI, to.RegNum, 1); + build->Emit(OP_JMP, 1); + size_t target = build->Emit(OP_LI, to.RegNum, 0); + build->Backpatch(patchspot, target); + return to; + } + else + { + assert(Operator == TK_OrOr); + build->Emit(OP_EQ_K, 0, op1.RegNum, zero); + // If op1 is not 0, skip evaluation of op2. + size_t patchspot = build->Emit(OP_JMP, 0, 0, 0); + + // Evaluate op2. + ExpEmit op2 = right->Emit(build); + assert(!op2.Konst); + build->FreeReg(op2.RegType, op2.RegNum); + + ExpEmit to(build, REGT_INT); + build->Emit(OP_EQ_K, 1, op2.RegNum, zero); + build->Emit(OP_JMP, 2); + build->Emit(OP_LI, to.RegNum, 0); + build->Emit(OP_JMP, 1); + size_t target = build->Emit(OP_LI, to.RegNum, 1); + build->Backpatch(patchspot, target); + return to; + } +} //========================================================================== // @@ -1490,6 +2106,20 @@ FxExpression *FxConditional::Resolve(FCompileContext& ctx) return e; } + if (ValueType == VAL_Float) + { + if (truex->ValueType != VAL_Float) + { + truex = new FxFloatCast(truex); + RESOLVE(truex, ctx); + } + if (falsex->ValueType != VAL_Float) + { + falsex = new FxFloatCast(falsex); + RESOLVE(falsex, ctx); + } + } + return this; } @@ -1508,6 +2138,78 @@ ExpVal FxConditional::EvalExpression (AActor *self) return e->EvalExpression(self); } +ExpEmit FxConditional::Emit(VMFunctionBuilder *build) +{ + ExpEmit out; + + // The true and false expressions ought to be assigned to the + // same temporary instead of being copied to it. Oh well; good enough + // for now. + ExpEmit cond = condition->Emit(build); + assert(cond.RegType == REGT_INT && !cond.Konst); + + // Test condition. + build->Emit(OP_EQ_K, 1, cond.RegNum, build->GetConstantInt(0)); + size_t patchspot = build->Emit(OP_JMP, 0); + + // Evaluate true expression. + if (truex->isConstant() && truex->ValueType == VAL_Int) + { + out = ExpEmit(build, REGT_INT); + build->EmitLoadInt(out.RegNum, truex->EvalExpression(NULL).GetInt()); + } + else + { + ExpEmit trueop = truex->Emit(build); + if (trueop.Konst) + { + assert(trueop.RegType == REGT_FLOAT); + out = ExpEmit(build, REGT_FLOAT); + build->Emit(OP_LKF, out.RegNum, trueop.RegNum); + } + else + { + // Use the register returned by the true condition as the + // target for the false condition. + out = trueop; + } + } + + // Evaluate false expression. + build->BackpatchToHere(patchspot); + if (falsex->isConstant() && falsex->ValueType == VAL_Int) + { + build->EmitLoadInt(out.RegNum, falsex->EvalExpression(NULL).GetInt()); + } + else + { + ExpEmit falseop = falsex->Emit(build); + if (falseop.Konst) + { + assert(falseop.RegType == REGT_FLOAT); + build->Emit(OP_LKF, out.RegNum, falseop.RegNum); + } + else + { + // Move result from the register returned by "false" to the one + // returned by "true" so that only one register is returned by + // this tree. + build->FreeReg(falseop.RegType, falseop.RegNum); + if (falseop.RegType == REGT_INT) + { + build->Emit(OP_MOVE, out.RegNum, falseop.RegNum, 0); + } + else + { + assert(falseop.RegType == REGT_FLOAT); + build->Emit(OP_MOVEF, out.RegNum, falseop.RegNum, 0); + } + } + } + + return out; +} + //========================================================================== // // @@ -1597,6 +2299,23 @@ ExpVal FxAbs::EvalExpression (AActor *self) return value; } +ExpEmit FxAbs::Emit(VMFunctionBuilder *build) +{ + ExpEmit absofsteal = val->Emit(build); + assert(!absofsteal.Konst); + ExpEmit out(build, absofsteal.RegType); + if (absofsteal.RegType == REGT_INT) + { + build->Emit(OP_ABS, out.RegNum, absofsteal.RegNum, 0); + } + else + { + assert(absofsteal.RegType == REGT_FLOAT); + build->Emit(OP_FLOP, out.RegNum, absofsteal.RegNum, FLOP_ABS); + } + return out; +} + //========================================================================== // // @@ -1676,6 +2395,85 @@ ExpVal FxRandom::EvalExpression (AActor *self) return val; } +int DecoRandom(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) +{ + assert(numparam >= 1 && numparam <= 3); + FRandom *rng = reinterpret_cast<FRandom *>(param[0].a); + if (numparam == 1) + { + ret->SetInt((*rng)()); + } + else if (numparam == 2) + { + int maskval = param[1].i; + ret->SetInt(rng->Random2(maskval)); + } + else if (numparam == 3) + { + int min = param[1].i, max = param[2].i; + if (max < min) + { + swap(max, min); + } + ret->SetInt((*rng)(max - min + 1) + min); + } + return 1; +} + +ExpEmit FxRandom::Emit(VMFunctionBuilder *build) +{ + // Find the DecoRandom function. If not found, create it and install it + // in Actor. + VMFunction *callfunc; + PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol("DecoRandom", false); + if (sym == NULL) + { + PSymbolVMFunction *symfunc = new PSymbolVMFunction("DecoRandom"); + VMNativeFunction *calldec = new VMNativeFunction(DecoRandom); + symfunc->Function = calldec; + sym = symfunc; + RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); + } + assert(sym->SymbolType == SYM_VMFunction); + assert(((PSymbolVMFunction *)sym)->Function != NULL); + callfunc = ((PSymbolVMFunction *)sym)->Function; + + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); + if (min != NULL && max != NULL) + { + ExpEmit op = min->Emit(build); + assert(op.RegType == REGT_INT); + if (op.Konst) + { + build->Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, op.RegNum); + } + else + { + build->FreeReg(REGT_INT, op.RegNum); + build->Emit(OP_PARAM, 0, REGT_INT, op.RegNum); + } + op = max->Emit(build); + assert(op.RegType == REGT_INT); + if (op.Konst) + { + build->Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, op.RegNum); + } + else + { + build->FreeReg(REGT_INT, op.RegNum); + build->Emit(OP_PARAM, 0, REGT_INT, op.RegNum); + } + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); + } + else + { + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 1, 1); + } + ExpEmit out(build, REGT_INT); + build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum); + return out; +} + //========================================================================== // // @@ -1723,6 +2521,84 @@ ExpVal FxFRandom::EvalExpression (AActor *self) return val; } +int DecoFRandom(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) +{ + assert(numparam == 1 || numparam == 3); + FRandom *rng = reinterpret_cast<FRandom *>(param[0].a); + + int random = (*rng)(0x40000000); + double frandom = random / double(0x40000000); + + if (numparam == 3) + { + double min = param[1].f, max = param[2].f; + if (max < min) + { + swap(max, min); + } + ret->SetFloat(frandom * (max - min) + min); + } + else + { + ret->SetFloat(frandom); + } + return 1; +} + +ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) +{ + // Find the DecoFRandom function. If not found, create it and install it + // in Actor. + VMFunction *callfunc; + PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol("DecoFRandom", false); + if (sym == NULL) + { + PSymbolVMFunction *symfunc = new PSymbolVMFunction("DecoFRandom"); + VMNativeFunction *calldec = new VMNativeFunction(DecoFRandom); + symfunc->Function = calldec; + sym = symfunc; + RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); + } + assert(sym->SymbolType == SYM_VMFunction); + assert(((PSymbolVMFunction *)sym)->Function != NULL); + callfunc = ((PSymbolVMFunction *)sym)->Function; + + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); + if (min != NULL && max != NULL) + { + ExpEmit op = min->Emit(build); + assert(op.RegType == REGT_FLOAT); + if (op.Konst) + { + build->Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, op.RegNum); + } + else + { + build->FreeReg(REGT_FLOAT, op.RegNum); + build->Emit(OP_PARAM, 0, REGT_FLOAT, op.RegNum); + } + op = max->Emit(build); + assert(op.RegType == REGT_FLOAT); + if (op.Konst) + { + build->Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, op.RegNum); + } + else + { + build->FreeReg(REGT_FLOAT, op.RegNum); + build->Emit(OP_PARAM, 0, REGT_FLOAT, op.RegNum); + } + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); + } + else + { + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 1, 1); + } + ExpEmit out(build, REGT_FLOAT); + build->Emit(OP_RESULT, 0, REGT_FLOAT, out.RegNum); + return out; +} + //========================================================================== // // @@ -1778,6 +2654,42 @@ ExpVal FxRandom2::EvalExpression (AActor *self) return maskval; } +ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) +{ + // Find the DecoRandom function. If not found, create it and install it + // in Actor. + VMFunction *callfunc; + PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol("DecoRandom", false); + if (sym == NULL) + { + PSymbolVMFunction *symfunc = new PSymbolVMFunction("DecoRandom"); + VMNativeFunction *calldec = new VMNativeFunction(DecoRandom); + symfunc->Function = calldec; + sym = symfunc; + RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); + } + assert(sym->SymbolType == SYM_VMFunction); + assert(((PSymbolVMFunction *)sym)->Function != NULL); + callfunc = ((PSymbolVMFunction *)sym)->Function; + + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); + ExpEmit op = mask->Emit(build); + assert(op.RegType == REGT_INT); + if (op.Konst) + { + build->Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, op.RegNum); + } + else + { + build->FreeReg(REGT_INT, op.RegNum); + build->Emit(OP_PARAM, 0, REGT_INT, op.RegNum); + } + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1); + ExpEmit out(build, REGT_INT); + build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum); + return out; +} + //========================================================================== // // @@ -1861,7 +2773,7 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) newex = new FxCVar(cv, ScriptPosition); } */ - // amd line specials + // and line specials else if ((num = P_FindLineSpecial(Identifier, NULL, NULL))) { ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as line special %d\n", Identifier.GetChars(), num); @@ -1924,6 +2836,12 @@ ExpVal FxSelf::EvalExpression (AActor *self) return ret; } +ExpEmit FxSelf::Emit(VMFunctionBuilder *build) +{ + // self is always the first pointer passed to the function; + return ExpEmit(0, REGT_POINTER); +} + //========================================================================== // // @@ -2004,7 +2922,6 @@ ExpVal FxGlobalVariable::EvalExpression (AActor *self) return ret; } - //========================================================================== // // @@ -2122,6 +3039,90 @@ ExpVal FxClassMember::EvalExpression (AActor *self) return ret; } +ExpEmit FxClassMember::Emit(VMFunctionBuilder *build) +{ + ExpEmit obj = classx->Emit(build); + assert(obj.RegType == REGT_POINTER); + + if (AddressRequested) + { + if (membervar->offset == 0) + { + return obj; + } + if (!obj.Konst) + { + build->FreeReg(obj.RegType, obj.RegNum); + } + ExpEmit out(build, REGT_POINTER); + build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, build->GetConstantInt((int)membervar->offset)); + return out; + } + + int offsetreg = build->GetConstantInt((int)membervar->offset); + ExpEmit loc, tmp; + + if (obj.Konst) + { + // If the situation where we are dereferencing a constant + // pointer is common, then it would probably be worthwhile + // to add new opcodes for those. But as of right now, I + // don't expect it to be a particularly common case. + ExpEmit newobj(build, REGT_POINTER); + build->Emit(OP_LKP, newobj.RegNum, obj.RegNum); + obj = newobj; + } + + switch (membervar->ValueType.Type) + { + case VAL_Int: + case VAL_Sound: + case VAL_Name: + case VAL_Color: + loc = ExpEmit(build, REGT_INT); + build->Emit(OP_LW, loc.RegNum, obj.RegNum, offsetreg); + break; + + case VAL_Bool: + loc = ExpEmit(build, REGT_INT); + // Some implementations have 1 byte bools, and others have + // 4 byte bools. For all I know, there might be some with + // 2 byte bools, too. + build->Emit((sizeof(bool) == 1 ? OP_LBU : sizeof(bool) == 2 ? OP_LHU : OP_LW), + loc.RegNum, obj.RegNum, offsetreg); + break; + + case VAL_Float: + loc = ExpEmit(build, REGT_FLOAT); + build->Emit(OP_LDP, loc.RegNum, obj.RegNum, offsetreg); + break; + + case VAL_Fixed: + loc = ExpEmit(build, REGT_FLOAT); + build->Emit(OP_LX, loc.RegNum, obj.RegNum, offsetreg); + break; + + case VAL_Angle: + loc = ExpEmit(build, REGT_FLOAT); + tmp = ExpEmit(build, REGT_INT); + build->Emit(OP_LW, tmp.RegNum, obj.RegNum, offsetreg); + build->Emit(OP_CAST, loc.RegNum, tmp.RegNum, CAST_I2F); + build->Emit(OP_MULF_RK, loc.RegNum, loc.RegNum, build->GetConstantFloat(90.0 / ANGLE_90)); + build->FreeReg(tmp.RegType, tmp.RegNum); + break; + + case VAL_Object: + case VAL_Class: + loc = ExpEmit(build, REGT_POINTER); + build->Emit(OP_LO, loc.RegNum, obj.RegNum, offsetreg); + break; + + default: + assert(0); + } + build->FreeReg(obj.RegType, obj.RegNum); + return loc; +} //========================================================================== @@ -2235,6 +3236,37 @@ ExpVal FxArrayElement::EvalExpression (AActor *self) return ret; } +ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) +{ + ExpEmit start = Array->Emit(build); + ExpEmit dest(build, REGT_INT); + if (start.Konst) + { + ExpEmit tmpstart(build, REGT_POINTER); + build->Emit(OP_LKP, tmpstart.RegNum, start.RegNum); + start = tmpstart; + } + if (index->isConstant()) + { + int indexval = index->EvalExpression(NULL).GetInt(); + if (indexval < 0 || indexval >= Array->ValueType.size) + { + I_Error("Array index out of bounds"); + } + indexval <<= 2; + build->Emit(OP_LW, dest.RegNum, start.RegNum, build->GetConstantInt(indexval)); + } + else + { + ExpEmit indexv(index->Emit(build)); + build->Emit(OP_SLL_RI, indexv.RegNum, indexv.RegNum, 2); + build->Emit(OP_BOUND, indexv.RegNum, Array->ValueType.size); + build->Emit(OP_LW_R, dest.RegNum, start.RegNum, indexv.RegNum); + build->FreeReg(indexv.RegType, indexv.RegNum); + } + build->FreeReg(start.RegType, start.RegNum); + return dest; +} //========================================================================== // @@ -2412,6 +3444,64 @@ ExpVal FxActionSpecialCall::EvalExpression (AActor *self) return ret; } +int DecoCallLineSpecial(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) +{ + assert(numparam > 2 && numparam < 7); + assert(numret == 1); + assert(param[0].Type == REGT_INT); + assert(param[1].Type == REGT_POINTER); + int v[5] = { 0 }; + + for (int i = 2; i < numparam; ++i) + { + v[i - 2] = param[i].i; + } + ret->SetInt(LineSpecials[param[0].i](NULL, reinterpret_cast<AActor*>(param[1].a), false, v[0], v[1], v[2], v[3], v[4])); + return 1; +} + +ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) +{ + assert(Self == NULL); + unsigned i = 0; + + build->Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, build->GetConstantInt(Special)); // pass special number + build->Emit(OP_PARAM, 0, REGT_POINTER, 0); // pass self + if (ArgList != NULL) + { + for (; i < ArgList->Size(); ++i) + { + ExpEmit arg((*ArgList)[i]->Emit(build)); + assert(arg.RegType == REGT_INT); + build->Emit(OP_PARAM, 0, arg.RegType | (arg.Konst ? REGT_KONST : 0), arg.RegNum); + if (!arg.Konst) + { + build->FreeReg(arg.RegType, arg.RegNum); + } + } + } + // Find the DecoCallLineSpecial function. If not found, create it and install it + // in Actor. + VMFunction *callfunc; + PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol("DecoCallLineSpecial", false); + if (sym == NULL) + { + PSymbolVMFunction *symfunc = new PSymbolVMFunction("DecoCallLineSpecial"); + VMNativeFunction *calldec = new VMNativeFunction(DecoCallLineSpecial); + symfunc->Function = calldec; + sym = symfunc; + RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); + } + assert(sym->SymbolType == SYM_VMFunction); + assert(((PSymbolVMFunction *)sym)->Function != NULL); + callfunc = ((PSymbolVMFunction *)sym)->Function; + + ExpEmit dest(build, REGT_INT); + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2 + i, 1); + build->Emit(OP_RESULT, 0, REGT_INT, dest.RegNum); + return dest; +} + //========================================================================== // // @@ -2466,6 +3556,19 @@ FxExpression *FxGlobalFunctionCall::Resolve(FCompileContext& ctx) delete this; return NULL; } + if ((*ArgList)[0]->isConstant()) + { + double v = (*ArgList)[0]->EvalExpression(NULL).GetFloat(); + v *= M_PI / 180.0; // convert from degrees to radians + v = (Name == NAME_Sin) ? sin(v) : cos(v); + FxExpression *x = new FxConstant(v, ScriptPosition); + delete this; + return x; + } + if ((*ArgList)[0]->ValueType == VAL_Int) + { + (*ArgList)[0] = new FxFloatCast((*ArgList)[0]); + } ValueType = VAL_Float; return this; } @@ -2490,6 +3593,15 @@ ExpVal FxGlobalFunctionCall::EvalExpression (AActor *self) return ret; } +ExpEmit FxGlobalFunctionCall::Emit(VMFunctionBuilder *build) +{ + ExpEmit v = (*ArgList)[0]->Emit(build); + assert(!v.Konst && v.RegType == REGT_FLOAT); + + build->Emit(OP_MULF_RK, v.RegNum, v.RegNum, build->GetConstantFloat(M_PI / 180.0)); + build->Emit(OP_FLOP, v.RegNum, v.RegNum, (Name == NAME_Sin) ? FLOP_SIN : FLOP_COS); + return v; +} //========================================================================== // @@ -2595,6 +3707,60 @@ ExpVal FxClassTypeCast::EvalExpression (AActor *self) return ret; } +int DecoNameToClass(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) +{ + assert(numparam == 2); + assert(numret == 1); + assert(param[0].Type == REGT_INT); + assert(param[1].Type == REGT_POINTER); + assert(ret->RegType == REGT_POINTER); + + FName clsname = ENamedName(param[0].i); + const PClass *cls = PClass::FindClass(clsname); + const PClass *desttype = reinterpret_cast<PClass *>(param[0].a); + + if (!cls->IsDescendantOf(desttype)) + { + Printf("class '%s' is not compatible with '%s'", clsname.GetChars(), desttype->TypeName.GetChars()); + cls = NULL; + } + ret->SetPointer(const_cast<PClass *>(cls)); + return 1; +} + +ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build) +{ + if (basex->ValueType != VAL_Name) + { + return ExpEmit(build->GetConstantAddress(NULL, ATAG_OBJECT), REGT_POINTER, true); + } + ExpEmit clsname = basex->Emit(build); + assert(!clsname.Konst); + ExpEmit dest(build, REGT_POINTER); + build->Emit(OP_PARAM, 0, clsname.RegType, clsname.RegNum); + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(const_cast<PClass *>(desttype), ATAG_OBJECT)); + + // Find the DecoNameToClass function. If not found, create it and install it + // in Actor. + VMFunction *callfunc; + PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol("DecoNameToClass", false); + if (sym == NULL) + { + PSymbolVMFunction *symfunc = new PSymbolVMFunction("DecoNameToClass"); + VMNativeFunction *calldec = new VMNativeFunction(DecoNameToClass); + symfunc->Function = calldec; + sym = symfunc; + RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); + } + assert(sym->SymbolType == SYM_VMFunction); + assert(((PSymbolVMFunction *)sym)->Function != NULL); + callfunc = ((PSymbolVMFunction *)sym)->Function; + + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1); + build->Emit(OP_RESULT, 0, REGT_POINTER, dest.RegNum); + build->FreeReg(clsname.RegType, clsname.RegNum); + return dest; +} //========================================================================== // @@ -2742,6 +3908,64 @@ ExpVal FxMultiNameState::EvalExpression (AActor *self) return ret; } +int DecoFindMultiNameState(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) +{ + assert(numparam > 1); + assert(numret == 1); + assert(param[0].Type == REGT_POINTER); + assert(ret->RegType == REGT_POINTER); + + FName *names = (FName *)alloca((numparam - 1) * sizeof(FName)); + for (int i = 1; i < numparam; ++i) + { + names[i - 1] = ENamedName(param[i].i); + } + AActor *self = reinterpret_cast<AActor *>(param[0].a); + FState *state = self->GetClass()->ActorInfo->FindState(numparam - 1, names); + if (state == NULL) + { + const char *dot = ""; + Printf("Jump target '"); + for (int i = 0; i < numparam - 1; i++) + { + Printf("%s%s", dot, names[i].GetChars()); + dot = "."; + } + Printf("' not found in %s\n", self->GetClass()->TypeName.GetChars()); + } + ret->SetPointer(state); + return 1; +} + +ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build) +{ + ExpEmit dest(build, REGT_POINTER); + build->Emit(OP_PARAM, 0, REGT_POINTER, 0); // pass self + for (unsigned i = 0; i < names.Size(); ++i) + { + build->Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, build->GetConstantInt(names[i])); + } + + // Find the DecoFindMultiNameState function. If not found, create it and install it + // in Actor. + VMFunction *callfunc; + PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol("DecoFindMultiNameState", false); + if (sym == NULL) + { + PSymbolVMFunction *symfunc = new PSymbolVMFunction("DecoFindMultiNameState"); + VMNativeFunction *calldec = new VMNativeFunction(DecoFindMultiNameState); + symfunc->Function = calldec; + sym = symfunc; + RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); + } + assert(sym->SymbolType == SYM_VMFunction); + assert(((PSymbolVMFunction *)sym)->Function != NULL); + callfunc = ((PSymbolVMFunction *)sym)->Function; + + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), names.Size() + 1, 1); + build->Emit(OP_RESULT, 0, REGT_POINTER, dest.RegNum); + return dest; +} //========================================================================== @@ -2903,4 +4127,3 @@ FxExpression *FStateExpressions::Get(int num) return expressions[num].expr; return NULL; } - diff --git a/src/zscript/vm.h b/src/zscript/vm.h index 156f7787a..1436977da 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -107,6 +107,7 @@ enum ATAG_AREGISTER, // pointer to an address register ATAG_STATE, // pointer to FState + ATAG_RNG, // pointer to FRandom }; class VMFunction : public DObject diff --git a/src/zscript/vmbuilder.cpp b/src/zscript/vmbuilder.cpp index d700b9908..fd0119055 100644 --- a/src/zscript/vmbuilder.cpp +++ b/src/zscript/vmbuilder.cpp @@ -61,10 +61,10 @@ VMScriptFunction *VMFunctionBuilder::MakeFunction() } // Assign required register space. - func->NumRegD = IntRegisters.MostUsed; - func->NumRegF = FloatRegisters.MostUsed; - func->NumRegA = AddressRegisters.MostUsed; - func->NumRegS = StringRegisters.MostUsed; + func->NumRegD = Registers[REGT_INT].MostUsed; + func->NumRegF = Registers[REGT_FLOAT].MostUsed; + func->NumRegA = Registers[REGT_POINTER].MostUsed; + func->NumRegS = Registers[REGT_STRING].MostUsed; func->MaxParam = MaxParam; // Technically, there's no reason why we can't end the function with @@ -274,7 +274,7 @@ VMFunctionBuilder::RegAvailability::RegAvailability() //========================================================================== // -// VMFunctionBuilder :: RegAvailibity :: GetReg +// VMFunctionBuilder :: RegAvailibity :: Get // // Gets one or more unused registers. If getting multiple registers, they // will all be consecutive. Returns -1 if there were not enough consecutive @@ -286,7 +286,7 @@ VMFunctionBuilder::RegAvailability::RegAvailability() // //========================================================================== -int VMFunctionBuilder::RegAvailability::GetReg(int count) +int VMFunctionBuilder::RegAvailability::Get(int count) { VM_UWORD mask; int i, firstbit; @@ -368,13 +368,13 @@ int VMFunctionBuilder::RegAvailability::GetReg(int count) //========================================================================== // -// VMFunctionBuilder :: RegAvailibity :: ReturnReg +// VMFunctionBuilder :: RegAvailibity :: Return // // Marks a range of registers as free again. // //========================================================================== -void VMFunctionBuilder::RegAvailability::ReturnReg(int reg, int count) +void VMFunctionBuilder::RegAvailability::Return(int reg, int count) { assert(count >= 1 && count <= 32); assert(reg >= 0 && reg + count <= 256); @@ -406,8 +406,108 @@ void VMFunctionBuilder::RegAvailability::ReturnReg(int reg, int count) } } -void VMFunctionBuilder::RegAvailability::Dump() +//========================================================================== +// +// VMFunctionBuilder :: Emit +// +// Just dumbly output an instruction. Returns instruction position, not +// byte position. (Because all instructions are exactly four bytes long.) +// +//========================================================================== + +size_t VMFunctionBuilder::Emit(int opcode, int opa, int opb, int opc) { - Printf("%032B %032B %032B %032B\n%032B %032B %032B %032B\n", - Used[0], Used[1], Used[2], Used[3], Used[4], Used[5], Used[6], Used[7]); + assert(opcode >= 0 && opcode < NUM_OPS); + assert(opa >= 0 && opa <= 255); + assert(opb >= 0 && opb <= 255); + assert(opc >= 0 && opc <= 255); + size_t loc = Code.Reserve(4); + VM_UBYTE *code = &Code[loc]; + code[0] = opcode; + code[1] = opa; + code[2] = opb; + code[3] = opc; + return loc / 4; +} + +size_t VMFunctionBuilder::Emit(int opcode, int opa, VM_SHALF opbc) +{ + assert(opcode >= 0 && opcode < NUM_OPS); + assert(opa >= 0 && opa <= 255); + assert(opbc >= -32768 && opbc <= 32767); + size_t loc = Code.Reserve(4); + VM_UBYTE *code = &Code[loc]; + code[0] = opcode; + code[1] = opa; + *(VM_SHALF *)&code[2] = opbc; + return loc / 4; +} + +size_t VMFunctionBuilder::Emit(int opcode, int opabc) +{ + assert(opcode >= 0 && opcode < NUM_OPS); + assert(opabc >= -(1 << 23) && opabc <= (1 << 24) - 1); + size_t loc = Code.Reserve(4); +#ifdef __BIG_ENDIAN__ + *(VM_UWORD *)&Code[loc] = (opabc & 0xFFFFFF) | (opcode << 24); +#else + *(VM_UWORD *)&Code[loc] = opcode | (opabc << 8); +#endif + return loc / 4; +} + +//========================================================================== +// +// VMFunctionBuilder :: EmitLoadInt +// +// Loads an integer constant into a register, using either an immediate +// value or a constant register, as appropriate. +// +//========================================================================== + +size_t VMFunctionBuilder::EmitLoadInt(int regnum, int value) +{ + assert(regnum >= 0 && regnum < Registers[REGT_INT].MostUsed); + if (value >= -32768 && value <= 32767) + { + return Emit(OP_LI, regnum, value); + } + else + { + return Emit(OP_LK, regnum, GetConstantInt(value)); + } +} + +//========================================================================== +// +// VMFunctionBuilder :: Backpatch +// +// Store a JMP instruction at <loc> that points at <target>. +// +//========================================================================== + +void VMFunctionBuilder::Backpatch(size_t loc, size_t target) +{ + assert(loc < Code.Size() / 4); + int offset = int(target - loc - 1); + assert(offset >= -(1 << 24) && offset <= (1 << 24) - 1); +#ifdef __BIG_ENDIAN__ + *(VM_UWORD *)&Code[loc * 4] = (offset & 0xFFFFFF) | (OP_JMP << 24); +#else + *(VM_UWORD *)&Code[loc * 4] = OP_JMP | (offset << 8); +#endif +} + +//========================================================================== +// +// VMFunctionBuilder :: BackpatchToHere +// +// Store a JMP instruction at <loc> that points to the current code gen +// location. +// +//========================================================================== + +void VMFunctionBuilder::BackpatchToHere(size_t loc) +{ + Backpatch(loc, Code.Size() / 4); } diff --git a/src/zscript/vmbuilder.h b/src/zscript/vmbuilder.h index 95d6f9dd3..af43cbf8b 100644 --- a/src/zscript/vmbuilder.h +++ b/src/zscript/vmbuilder.h @@ -11,9 +11,8 @@ public: { public: RegAvailability(); - int GetReg(int count); // Returns the first register in the range - void ReturnReg(int reg, int count); - void Dump(); + int Get(int count); // Returns the first register in the range + void Return(int reg, int count); private: VM_UWORD Used[256/32]; // Bitmap of used registers (bit set means reg is used) @@ -35,6 +34,12 @@ public: // Returns the address of the newly-emitted instruction. size_t Emit(int opcode, int opa, int opb, int opc); + size_t Emit(int opcode, int opa, VM_SHALF opbc); + size_t Emit(int opcode, int opabc); + size_t EmitLoadInt(int regnum, int value); + + void Backpatch(size_t addr, size_t target); + void BackpatchToHere(size_t addr); // Write out complete constant tables. void FillIntConstants(int *konst); @@ -46,10 +51,10 @@ public: void ParamChange(int delta); // Track available registers. - RegAvailability IntRegisters; - RegAvailability FloatRegisters; - RegAvailability AddressRegisters; - RegAvailability StringRegisters; + RegAvailability Registers[4]; + + // Free a register. + void FreeReg(int regtype, int regnum); private: struct AddrKonst diff --git a/src/zscript/vmexec.cpp b/src/zscript/vmexec.cpp index 9c32b4fc5..8835afcc8 100644 --- a/src/zscript/vmexec.cpp +++ b/src/zscript/vmexec.cpp @@ -30,8 +30,8 @@ #define JMPOFS(x) ((*(VM_SWORD *)(x) >> 6) & ~3) #endif -#define KC (konst[C]) -#define RC (reg.i[C]) +#define KC (konstd[C]) +#define RC (reg.d[C]) #define PA (reg.a[A]) #define PB (reg.a[B]) @@ -61,11 +61,12 @@ enum X_READ_NIL, X_WRITE_NIL, X_TOO_MANY_TRIES, + X_ARRAY_OUT_OF_BOUNDS }; #define GETADDR(a,o,x) \ - if (a == 0) { THROW(x); } \ - ptr = (VM_SBYTE *)a + x \ + if (a == NULL) { THROW(x); } \ + ptr = (VM_SBYTE *)a + o static const VM_UWORD ZapTable[16] = { diff --git a/src/zscript/vmexec.h b/src/zscript/vmexec.h index 350845e5d..e300e6644 100644 --- a/src/zscript/vmexec.h +++ b/src/zscript/vmexec.h @@ -586,6 +586,13 @@ begin: assert(0); NEXTOP; + OP(BOUND): + if (reg.d[a] >= BC) + { + THROW(X_ARRAY_OUT_OF_BOUNDS); + } + NEXTOP; + OP(CONCAT): ASSERTS(a); ASSERTS(B); ASSERTS(C); { diff --git a/src/zscript/vmops.h b/src/zscript/vmops.h index f7d821bb9..00c6f5d13 100644 --- a/src/zscript/vmops.h +++ b/src/zscript/vmops.h @@ -73,7 +73,7 @@ xx(DYNCAST_K, dyncast,RPRPKP), xx(TEST, test, RII16), // if (dA != BC) then pc++ xx(JMP, jmp, I24), // pc += ABC -- The ABC fields contain a signed 24-bit offset. xx(IJMP, ijmp, RII16), // pc += dA + BC -- BC is a signed offset. The target instruction must be a JMP. -xx(PARAM, param, __BCP), // push parameter encoded in BC for function call or result for return +xx(PARAM, param, __BCP), // push parameter encoded in BC for function call (B=regtype, C=regnum) xx(CALL, call, RPI8I8), // Call function pkA with parameter count B and expected result count C xx(CALL_K, call, KPI8I8), xx(RESULT, result, __BCP), // Result should go in register encoded in BC (in caller, after CALL) @@ -87,6 +87,7 @@ xx(CATCH, catch, CATCH), // A == 0: continue search on next try // A == 2: (pB == <type of exception thrown>) then pc++ ; next instruction must JMP to another CATCH // A == 3: (pkB == <type of exception thrown>) then pc++ ; next instruction must JMP to another CATCH // for A > 0, exception is stored in pC +xx(BOUND, bound, RII16), // if rA >= BC, throw exception // String instructions. xx(CONCAT, concat, RSRSRS), // sA = sB.. ... ..sC @@ -129,7 +130,7 @@ xx(MAX_RR, max, RIRIRI), // dA = max(dB,dkC) xx(MAX_RK, max, RIRIKI), xx(ABS, abs, RIRI), // dA = abs(dB) xx(NEG, neg, RIRI), // dA = -dB -xx(NOT, not, RIRI), // dA = !dB +xx(NOT, not, RIRI), // dA = ~dB xx(SEXT, sext, RIRII8), // dA = dB, sign extended by shifting left then right by C xx(ZAP_R, zap, RIRIRI), // dA = dB, with bytes zeroed where bits in C/dC are one xx(ZAP_I, zap, RIRII8), From 4fa94390d00b90cc5c4ec4924389f28219263654 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 14 Oct 2009 02:39:13 +0000 Subject: [PATCH 009/232] - Add parameter tracking to VMBuilder::Emit(). SVN r1910 (scripting) --- src/zscript/vmbuilder.cpp | 8 ++++++++ src/zscript/vmbuilder.h | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/zscript/vmbuilder.cpp b/src/zscript/vmbuilder.cpp index fd0119055..3f1757828 100644 --- a/src/zscript/vmbuilder.cpp +++ b/src/zscript/vmbuilder.cpp @@ -427,6 +427,14 @@ size_t VMFunctionBuilder::Emit(int opcode, int opa, int opb, int opc) code[1] = opa; code[2] = opb; code[3] = opc; + if (opcode == OP_PARAM) + { + ParamChange(1); + } + else if (opcode == OP_CALL || opcode == OP_CALL_K) + { + ParamChange(-opb); + } return loc / 4; } diff --git a/src/zscript/vmbuilder.h b/src/zscript/vmbuilder.h index af43cbf8b..a1c6dfe3f 100644 --- a/src/zscript/vmbuilder.h +++ b/src/zscript/vmbuilder.h @@ -47,9 +47,6 @@ public: void FillAddressConstants(FVoidObj *konst, VM_ATAG *tags); void FillStringConstants(FString *strings); - // PARAM increases ActiveParam; CALL decreases it. - void ParamChange(int delta); - // Track available registers. RegAvailability Registers[4]; @@ -77,6 +74,9 @@ private: int ActiveParam; TArray<VM_UBYTE> Code; + + // PARAM increases ActiveParam; CALL decreases it. + void ParamChange(int delta); }; #endif From 85cc335725d41c7777b7f819c0b0bdeb3f351298 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Thu, 15 Oct 2009 03:58:23 +0000 Subject: [PATCH 010/232] - Added dummy code generation for states that pass parameters to action functions. Currently, they're only good for disassembly and pasting into a proper text editor for viewing. - Fixed some problems with the FxExpression emitters that were revealed by actually using them on the standard actors. SVN r1911 (scripting) --- src/d_dehacked.cpp | 4 +- src/p_states.cpp | 14 +-- src/thingdef/thingdef.cpp | 37 +++++++- src/thingdef/thingdef.h | 12 ++- src/thingdef/thingdef_exp.h | 3 +- src/thingdef/thingdef_expression.cpp | 68 ++++++++++++--- src/thingdef/thingdef_states.cpp | 67 ++++++++------- src/zscript/vm.h | 1 + src/zscript/vmbuilder.cpp | 4 + src/zscript/vmbuilder.h | 2 +- src/zscript/vmdisasm.cpp | 123 ++++++++++++++++++++------- 11 files changed, 250 insertions(+), 85 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 3c51af2b9..c2859ef78 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -611,8 +611,6 @@ enum MBFCodePointers SMMU_NailBomb, // No misc, but it's basically A_Explode with an added effect }; -int PrepareStateParameters(FState * state, int numparams, const PClass *cls);// Should probably be in a .h file. - // Hacks the parameter list for the given state so as to convert MBF-args (misc1 and misc2) into real args. void SetDehParams(FState * state, int codepointer) @@ -636,6 +634,7 @@ void SetDehParams(FState * state, int codepointer) // Bleargh! This will all have to be redone once scripting works // Not sure exactly why the index for a state is greater by one point than the index for a symbol. +#if 0 DPrintf("SetDehParams: Paramindex is %d, default is %d.\n", state->ParameterIndex-1, sym->defaultparameterindex); if (state->ParameterIndex-1 == sym->defaultparameterindex) @@ -716,6 +715,7 @@ void SetDehParams(FState * state, int codepointer) // This simply should not happen. Printf("Unmanaged dehacked codepointer alias num %i\n", codepointer); } +#endif } static int PatchThing (int thingy) diff --git a/src/p_states.cpp b/src/p_states.cpp index f3a99798f..9d5be4a5e 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -817,13 +817,16 @@ bool FStateDefinitions::SetLoop() //========================================================================== // // AddStates -// adds some state to the current definition set +// +// Adds some state to the current definition set. Returns the number of +// states added. Positive = no errors, negative = errors. // //========================================================================== -bool FStateDefinitions::AddStates(FState *state, const char *framechars) +int FStateDefinitions::AddStates(FState *state, const char *framechars) { bool error = false; + int count = 0; while (*framechars) { int frame; @@ -834,17 +837,18 @@ bool FStateDefinitions::AddStates(FState *state, const char *framechars) frame = ((*framechars)&223)-'A'; framechars++; - if (frame<0 || frame>28) + if (frame < 0 || frame > 28) { frame = 0; error = true; } - state->Frame=(state->Frame&(SF_FULLBRIGHT))|frame; + state->Frame = (state->Frame&(SF_FULLBRIGHT)) | frame; StateArray.Push(*state); + ++count; } laststate = &StateArray[StateArray.Size() - 1]; - return !error; + return !error ? count : -count; } //========================================================================== diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 5dcab6c60..21f17a5f3 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -64,6 +64,7 @@ #include "thingdef.h" #include "thingdef_exp.h" #include "a_sharedglobal.h" +#include "vmbuilder.h" // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- void InitThingdef(); @@ -279,8 +280,42 @@ void FinishActor(const FScriptPosition &sc, FActorInfo *info, Baggage &bag) static void FinishThingdef() { int errorcount = StateParams.ResolveAll(); + unsigned i, j; - for (unsigned i = 0;i < PClass::m_Types.Size(); i++) + for (i = 0; i < StateTempCalls.Size(); ++i) + { + FStateTempCall *tcall = StateTempCalls[i]; + FCompileContext ctx(tcall->ActorInfo->Class, true); + for (j = 0; j < tcall->Parameters.Size(); ++j) + { + tcall->Parameters[j]->Resolve(ctx); + } + VMFunctionBuilder buildit; + for (j = 0; j < tcall->Parameters.Size(); ++j) + { + FxExpression *p = /*new FxParameter*/(tcall->Parameters[j]); + p->Emit(&buildit); + delete p; + } + // FIXME: Call a real function + buildit.Emit(OP_CALL_K, buildit.GetConstantAddress(NULL, ATAG_OBJECT), j, 0); + VMScriptFunction *func = buildit.MakeFunction(); +#if 1 + const char *marks = "======================================================="; + char label[40]; + int labellen = mysnprintf(label, countof(label), "Function %s.States[%d] (*%d)", + tcall->ActorInfo->Class->TypeName.GetChars(), + tcall->FirstState, tcall->NumStates); + Printf("\n%.*s %s %.*s", MAX(3, 38 - labellen / 2), marks, label, MAX(3, 38 - labellen / 2), marks); + VMDumpConstants(func); + Printf("\nDisassembly:\n"); + VMDisasm(func->Code, func->NumCodeBytes / 4, func); +#endif + //if(i==6) I_Error("Poop"); + } + I_Error("Poop"); + + for (i = 0; i < PClass::m_Types.Size(); i++) { PClass * ti = PClass::m_Types[i]; diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index 2f573f8e9..43b78c4bd 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -99,9 +99,8 @@ public: bool SetStop(); bool SetWait(); bool SetLoop(); - bool AddStates(FState *state, const char *framechars); + int AddStates(FState *state, const char *framechars); int GetStateCount() const { return StateArray.Size(); } - }; //========================================================================== @@ -110,6 +109,15 @@ public: // //========================================================================== +struct FStateTempCall +{ + FActorInfo *ActorInfo; + int FirstState; + int NumStates; + TArray<FxExpression *> Parameters; +}; +extern TDeletingArray<FStateTempCall *> StateTempCalls; + struct FStateExpression { FxExpression *expr; diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index d75000d41..53c719de7 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -314,6 +314,7 @@ public: return true; } ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; @@ -439,7 +440,7 @@ public: FxBinary(int, FxExpression*, FxExpression*); ~FxBinary(); bool ResolveLR(FCompileContext& ctx, bool castnumeric); - void Promote(); + void Promote(FCompileContext &ctx); }; //========================================================================== diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index eb02a1892..34f4a4080 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -79,7 +79,7 @@ DEFINE_MEMBER_VARIABLE(Score, AActor) DEFINE_MEMBER_VARIABLE(uservar, AActor) ExpEmit::ExpEmit(VMFunctionBuilder *build, int type) -: RegNum(build->Registers[type].Get(1)), RegType(type) +: RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false) { } @@ -371,7 +371,7 @@ ExpEmit FxParameter::Emit(VMFunctionBuilder *build) } else if (val.Type == VAL_Float) { - build->Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, build->GetConstantFloat(val.Int)); + build->Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, build->GetConstantFloat(val.Float)); } else if (val.Type == VAL_Class || val.Type == VAL_Object) { @@ -390,11 +390,15 @@ ExpEmit FxParameter::Emit(VMFunctionBuilder *build) { ExpEmit where = Operand->Emit(build); - if (where.RegNum == REGT_NIL) + if (where.RegType == REGT_NIL) { ScriptPosition.Message(MSG_ERROR, "Attempted to pass a non-value"); build->Emit(OP_PARAM, 0, where.RegType, where.RegNum); } + else + { + build->Emit(OP_PARAM, 0, where.RegType, where.RegNum); + } } return ExpEmit(); } @@ -445,6 +449,40 @@ FxExpression *FxConstant::MakeConstant(PSymbol *sym, const FScriptPosition &pos) return x; } +ExpEmit FxConstant::Emit(VMFunctionBuilder *build) +{ + ExpEmit out; + + out.Konst = true; + if (value.Type == VAL_Int || value.Type == VAL_Sound || value.Type == VAL_Name || value.Type == VAL_Color) + { + out.RegType = REGT_INT; + out.RegNum = build->GetConstantInt(value.Int); + } + else if (value.Type == VAL_Float) + { + out.RegType = REGT_FLOAT; + out.RegNum = build->GetConstantFloat(value.Float); + } + else if (value.Type == VAL_Class || value.Type == VAL_Object) + { + out.RegType = REGT_POINTER; + out.RegNum = build->GetConstantAddress(value.pointer, ATAG_OBJECT); + } + else if (value.Type == VAL_State) + { + out.RegType = REGT_POINTER; + out.RegNum = build->GetConstantAddress(value.pointer, ATAG_STATE); + } + else + { + ScriptPosition.Message(MSG_ERROR, "Cannot emit needed constant"); + out.RegType = REGT_NIL; + out.RegNum = 0; + } + return out; +} + //========================================================================== // // @@ -610,6 +648,7 @@ ExpEmit FxFloatCast::Emit(VMFunctionBuilder *build) ExpEmit from = basex->Emit(build); assert(!from.Konst); assert(basex->ValueType == VAL_Int); + build->FreeReg(from.RegType, from.RegNum); ExpEmit to(build, REGT_FLOAT); build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_I2F); return to; @@ -1033,15 +1072,15 @@ bool FxBinary::ResolveLR(FCompileContext& ctx, bool castnumeric) return true; } -void FxBinary::Promote() +void FxBinary::Promote(FCompileContext &ctx) { if (left->ValueType == VAL_Float && right->ValueType == VAL_Int) { - right = new FxFloatCast(right); + right = (new FxFloatCast(right))->Resolve(ctx); } else if (left->ValueType == VAL_Int && right->ValueType == VAL_Float) { - left = new FxFloatCast(left); + left = (new FxFloatCast(left))->Resolve(ctx); } } @@ -1103,7 +1142,7 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx) } } - Promote(); + Promote(ctx); return this; } @@ -1280,7 +1319,7 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) } } - Promote(); + Promote(ctx); return this; } @@ -1342,6 +1381,7 @@ ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build) swap(op1, op2); } assert(!op1.Konst); + build->FreeReg(op1.RegType, op1.RegNum); if (!op2.Konst) { build->FreeReg(op2.RegType, op2.RegNum); @@ -1451,7 +1491,7 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) delete this; return e; } - Promote(); + Promote(ctx); ValueType = VAL_Int; return this; } @@ -1604,7 +1644,7 @@ cont: delete this; return e; } - Promote(); + Promote(ctx); ValueType = VAL_Int; return this; } @@ -2357,6 +2397,14 @@ FxExpression *FxRandom::Resolve(FCompileContext &ctx) CHECKRESOLVED(); if (min && max) { + if (min->ValueType != VAL_Int) + { + min = new FxIntCast(min); + } + if (max->ValueType != VAL_Int) + { + max = new FxIntCast(max); + } RESOLVE(min, ctx); RESOLVE(max, ctx); ABORT(min && max); diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index d7252c419..82f8dd28c 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -56,18 +56,7 @@ #include "colormatcher.h" #include "thingdef_exp.h" -//========================================================================== -//*** -// PrepareStateParameters -// creates an empty parameter list for a parameterized function call -// -//========================================================================== -int PrepareStateParameters(FState * state, int numparams, const PClass *cls) -{ - int paramindex=StateParams.Reserve(numparams, cls); - state->ParameterIndex = paramindex+1; - return paramindex; -} +TDeletingArray<FStateTempCall *> StateTempCalls; //========================================================================== //*** @@ -75,7 +64,7 @@ int PrepareStateParameters(FState * state, int numparams, const PClass *cls) // handles action specials as code pointers // //========================================================================== -bool DoActionSpecials(FScanner &sc, FState & state, Baggage &bag) +bool DoActionSpecials(FScanner &sc, FState & state, Baggage &bag, FStateTempCall *tcall) { int i; int min_args, max_args; @@ -85,17 +74,14 @@ bool DoActionSpecials(FScanner &sc, FState & state, Baggage &bag) if (special > 0 && min_args >= 0) { - - int paramindex=PrepareStateParameters(&state, 6, bag.Info->Class); - - StateParams.Set(paramindex, new FxConstant(special, sc)); + tcall->Parameters.Push(new FxParameter(new FxConstant(special, sc))); // Make this consistent with all other parameter parsing if (sc.CheckToken('(')) { for (i = 0; i < 5;) { - StateParams.Set(paramindex+i+1, ParseExpression (sc, bag.Info->Class)); + tcall->Parameters.Push(new FxParameter(ParseExpression(sc, bag.Info->Class))); i++; if (!sc.CheckToken (',')) break; } @@ -153,7 +139,8 @@ void ParseStates(FScanner &sc, FActorInfo * actor, AActor * defaults, Baggage &b { FString statestring; FState state; - char lastsprite[5]=""; + char lastsprite[5] = ""; + FStateTempCall *tcall = NULL; sc.MustGetStringName ("{"); sc.SetEscape(false); // disable escape sequences in the state parser @@ -238,6 +225,10 @@ do_stop: sc.MustGetNumber(); state.Tics = clamp<int>(sc.Number, -1, 32767); + if (tcall == NULL) + { + tcall = new FStateTempCall; + } while (sc.GetString() && !sc.Crossed) { @@ -262,7 +253,7 @@ do_stop: // Make the action name lowercase to satisfy the gperf hashers strlwr (sc.String); - if (DoActionSpecials(sc, state, bag)) + if (DoActionSpecials(sc, state, bag, tcall)) { goto endofstate; } @@ -292,19 +283,19 @@ do_stop: } } - int paramindex = PrepareStateParameters(&state, numparams, bag.Info->Class); - int paramstart = paramindex; +// int paramindex = PrepareStateParameters(&state, numparams, bag.Info->Class); +// int paramstart = paramindex; bool varargs = params[numparams - 1] == '+'; - int varargcount=0; + int argcount = 0; if (varargs) { - paramindex++; +// paramindex++; } else if (afd->defaultparameterindex > -1) { - StateParams.Copy(paramindex, afd->defaultparameterindex, int(afd->Arguments.Len())); +// StateParams.Copy(paramindex, afd->defaultparameterindex, int(afd->Arguments.Len())); } while (*params) @@ -338,19 +329,17 @@ do_stop: // Use the generic parameter parser for everything else x = ParseParameter(sc, bag.Info->Class, *params, false); } - StateParams.Set(paramindex++, x); +// StateParams.Set(paramindex++, x); + tcall->Parameters.Push(new FxParameter(x)); params++; - if (varargs) - { - varargcount++; - } + argcount++; if (*params) { if (*params == '+') { if (sc.CheckString(")")) { - StateParams.Set(paramstart, new FxConstant(varargcount, sc)); +// StateParams.Set(paramstart, new FxConstant(argcount, sc)); goto endofstate; } params--; @@ -380,12 +369,26 @@ do_stop: } sc.UnGet(); endofstate: - if (!bag.statedef.AddStates(&state, statestring)) + int count = bag.statedef.AddStates(&state, statestring); + if (count < 0) { sc.ScriptError ("Invalid frame character string '%s'", statestring.GetChars()); + count = -count; + } + if (tcall->Parameters.Size() != 0) + { + tcall->ActorInfo = actor; + tcall->FirstState = bag.statedef.GetStateCount() - count; + tcall->NumStates = count; + StateTempCalls.Push(tcall); + tcall = NULL; } } } + if (tcall != NULL) + { + delete tcall; + } sc.SetEscape(true); // re-enable escape sequences } diff --git a/src/zscript/vm.h b/src/zscript/vm.h index 1436977da..9912637dc 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -812,6 +812,7 @@ void VMSelectEngine(EVMEngine engine); extern int (*VMExec)(VMFrameStack *stack, const VM_UBYTE *pc, VMReturn *ret, int numret); void VMFillParams(VMValue *params, VMFrame *callee, int numparam); +void VMDumpConstants(const VMScriptFunction *func); void VMDisasm(const VM_UBYTE *code, int codesize, const VMScriptFunction *func); #endif diff --git a/src/zscript/vmbuilder.cpp b/src/zscript/vmbuilder.cpp index 3f1757828..114f27d8e 100644 --- a/src/zscript/vmbuilder.cpp +++ b/src/zscript/vmbuilder.cpp @@ -227,6 +227,10 @@ int VMFunctionBuilder::GetConstantString(FString val) int VMFunctionBuilder::GetConstantAddress(void *ptr, VM_ATAG tag) { + if (ptr == NULL) + { // Make all NULL pointers generic. (Or should we allow typed NULLs?) + tag = ATAG_GENERIC; + } AddrKonst *locp = AddressConstants.CheckKey(ptr); if (locp != NULL) { diff --git a/src/zscript/vmbuilder.h b/src/zscript/vmbuilder.h index a1c6dfe3f..e09b8bfe8 100644 --- a/src/zscript/vmbuilder.h +++ b/src/zscript/vmbuilder.h @@ -51,7 +51,7 @@ public: RegAvailability Registers[4]; // Free a register. - void FreeReg(int regtype, int regnum); + void FreeReg(int regtype, int regnum) { Registers[regtype].Return(regnum, 1); } private: struct AddrKonst diff --git a/src/zscript/vmdisasm.cpp b/src/zscript/vmdisasm.cpp index 7ca2a3dc3..39f271084 100644 --- a/src/zscript/vmdisasm.cpp +++ b/src/zscript/vmdisasm.cpp @@ -101,6 +101,63 @@ const VMOpInfo OpInfo[NUM_OPS] = static int print_reg(int col, int arg, int mode, int immshift, const VMScriptFunction *func); +void VMDumpConstants(const VMScriptFunction *func) +{ + char tmp[21]; + int i, j, k, kk; + + if (func->KonstD != NULL && func->NumKonstD != 0) + { + Printf("\nConstant integers:\n"); + kk = (func->NumKonstD + 3) / 4; + for (i = 0; i < kk; ++i) + { + for (j = 0, k = i; j < 4 && k < func->NumKonstD; j++, k += kk) + { + mysnprintf(tmp, countof(tmp), "%3d. %d", k, func->KonstD[k]); + Printf("%-20s", tmp); + } + Printf("\n"); + } + } + if (func->KonstF != NULL && func->NumKonstF != 0) + { + Printf("\nConstant floats:\n"); + kk = (func->NumKonstF + 3) / 4; + for (i = 0; i < kk; ++i) + { + for (j = 0, k = i; j < 4 && k < func->NumKonstF; j++, k += kk) + { + mysnprintf(tmp, countof(tmp), "%3d. %.16f", k, func->KonstF[k]); + Printf("%-20s", tmp); + } + Printf("\n"); + } + } + if (func->KonstA != NULL && func->NumKonstA != 0) + { + Printf("\nConstant addresses:\n"); + kk = (func->NumKonstA + 3) / 4; + for (i = 0; i < kk; ++i) + { + for (j = 0, k = i; j < 4 && k < func->NumKonstA; j++, k += kk) + { + mysnprintf(tmp, countof(tmp), "%3d. %p", k, func->KonstA[k]); + Printf("%-20s", tmp); + } + Printf("\n"); + } + } + if (func->KonstS != NULL && func->NumKonstS != 0) + { + Printf("\nConstant strings:\n"); + for (i = 0; i < func->NumKonstS; ++i) + { + Printf("%3d. %s\n", func->KonstS[k].GetChars()); + } + } +} + void VMDisasm(const VM_UBYTE *code, int codesize, const VMScriptFunction *func) { const char *name; @@ -129,13 +186,13 @@ void VMDisasm(const VM_UBYTE *code, int codesize, const VMScriptFunction *func) a &= CMP_CHECK | CMP_APPROX; } - printf("%08x: %02x%02x%02x%02x %-8s", i, code[i], code[i+1], code[i+2], code[i+3], name); + Printf("%08x: %02x%02x%02x%02x %-8s", i, code[i], code[i+1], code[i+2], code[i+3], name); col = 0; switch (code[i]) { case OP_JMP: case OP_TRY: - col = printf("%08x", i + 4 + JMPOFS(&code[i])); + col = Printf("%08x", i + 4 + JMPOFS(&code[i])); break; case OP_RET: @@ -151,7 +208,7 @@ void VMDisasm(const VM_UBYTE *code, int codesize, const VMScriptFunction *func) col += print_reg(col, *(VM_UHALF *)&code[i+2], MODE_PARAM, 16, func); if (code[i+2] & REGT_FINAL) { - col += printf(" [final]"); + col += Printf(" [final]"); } } } @@ -229,14 +286,14 @@ void VMDisasm(const VM_UBYTE *code, int codesize, const VMScriptFunction *func) { col = 30; } - printf("%*c", 30 - col, ';'); + Printf("%*c", 30 - col, ';'); if (code[i] == OP_JMP || code[i] == OP_TRY) { - printf("%d\n", JMPOFS(&code[i]) >> 2); + Printf("%d\n", JMPOFS(&code[i]) >> 2); } else { - printf("%d,%d,%d\n", code[i+1], code[i+2], code[i+3]); + Printf("%d,%d,%d\n", code[i+1], code[i+2], code[i+3]); } } } @@ -249,57 +306,57 @@ static int print_reg(int col, int arg, int mode, int immshift, const VMScriptFun } if (col > 0) { - col = printf(","); + col = Printf(","); } switch(mode) { case MODE_I: - return col+printf("d%d", arg); + return col+Printf("d%d", arg); case MODE_F: - return col+printf("f%d", arg); + return col+Printf("f%d", arg); case MODE_S: - return col+printf("s%d", arg); + return col+Printf("s%d", arg); case MODE_P: - return col+printf("a%d", arg); + return col+Printf("a%d", arg); case MODE_V: - return col+printf("v%d", arg); + return col+Printf("v%d", arg); case MODE_KI: if (func != NULL) { - return col+printf("%d", func->KonstD[arg]); + return col+Printf("%d", func->KonstD[arg]); } - return printf("kd%d", arg); + return Printf("kd%d", arg); case MODE_KF: if (func != NULL) { - return col+printf("%f", func->KonstF[arg]); + return col+Printf("%f", func->KonstF[arg]); } - return col+printf("kf%d", arg); + return col+Printf("kf%d", arg); case MODE_KS: if (func != NULL) { - return col+printf("\"%s\"", func->KonstS[arg].GetChars()); + return col+Printf("\"%s\"", func->KonstS[arg].GetChars()); } - return col+printf("ks%d", arg); + return col+Printf("ks%d", arg); case MODE_KP: if (func != NULL) { - return col+printf("%p", func->KonstA[arg]); + return col+Printf("%p", func->KonstA[arg]); } - return col+printf("ka%d", arg); + return col+Printf("ka%d", arg); case MODE_KV: if (func != NULL) { - return col+printf("(%f,%f,%f)", func->KonstF[arg], func->KonstF[arg+1], func->KonstF[arg+2]); + return col+Printf("(%f,%f,%f)", func->KonstF[arg], func->KonstF[arg+1], func->KonstF[arg+2]); } - return col+printf("kv%d", arg); + return col+Printf("kv%d", arg); case MODE_IMMS: - return col+printf("%d", (arg << immshift) >> immshift); + return col+Printf("%d", (arg << immshift) >> immshift); case MODE_IMMZ: - return col+printf("%d", arg); + return col+Printf("%d", arg); case MODE_PARAM: { @@ -308,15 +365,15 @@ static int print_reg(int col, int arg, int mode, int immshift, const VMScriptFun switch (p.RegType & (REGT_TYPE | REGT_KONST | REGT_MULTIREG)) { case REGT_INT: - return col+printf("d%d", p.RegNum); + return col+Printf("d%d", p.RegNum); case REGT_FLOAT: - return col+printf("f%d", p.RegNum); + return col+Printf("f%d", p.RegNum); case REGT_STRING: - return col+printf("s%d", p.RegNum); + return col+Printf("s%d", p.RegNum); case REGT_POINTER: - return col+printf("a%d", p.RegNum); + return col+Printf("a%d", p.RegNum); case REGT_FLOAT | REGT_MULTIREG: - return col+printf("v%d", p.RegNum); + return col+Printf("v%d", p.RegNum); case REGT_INT | REGT_KONST: return col+print_reg(0, p.RegNum, MODE_KI, 0, func); case REGT_FLOAT | REGT_KONST: @@ -328,7 +385,11 @@ static int print_reg(int col, int arg, int mode, int immshift, const VMScriptFun case REGT_FLOAT | REGT_MULTIREG | REGT_KONST: return col+print_reg(0, p.RegNum, MODE_KV, 0, func); default: - return col+printf("param[t=%d,%c,%c,n=%d]", + if (p.RegType == REGT_NIL) + { + return col+Printf("nil"); + } + return col+Printf("param[t=%d,%c,%c,n=%d]", p.RegType & REGT_TYPE, p.RegType & REGT_KONST ? 'k' : 'r', p.RegType & REGT_MULTIREG ? 'm' : 's', @@ -337,7 +398,7 @@ static int print_reg(int col, int arg, int mode, int immshift, const VMScriptFun } default: - return col+printf("$%d", arg); + return col+Printf("$%d", arg); } return col; } From caa5f6dbdc13fae6b6883317765715a1653050b2 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Thu, 15 Oct 2009 21:23:59 +0000 Subject: [PATCH 011/232] - Send disassembly to a file, since it gets way too slow when sending a disassembly of every single thing to the rich edit control. SVN r1917 (scripting) --- src/thingdef/thingdef.cpp | 10 +-- src/zscript/vm.h | 4 +- src/zscript/vmdisasm.cpp | 137 ++++++++++++++++++++++---------------- 3 files changed, 86 insertions(+), 65 deletions(-) diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 21f17a5f3..b8ae5fc8f 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -282,6 +282,7 @@ static void FinishThingdef() int errorcount = StateParams.ResolveAll(); unsigned i, j; + FILE *dump = fopen("disasm.txt", "w"); for (i = 0; i < StateTempCalls.Size(); ++i) { FStateTempCall *tcall = StateTempCalls[i]; @@ -306,13 +307,14 @@ static void FinishThingdef() int labellen = mysnprintf(label, countof(label), "Function %s.States[%d] (*%d)", tcall->ActorInfo->Class->TypeName.GetChars(), tcall->FirstState, tcall->NumStates); - Printf("\n%.*s %s %.*s", MAX(3, 38 - labellen / 2), marks, label, MAX(3, 38 - labellen / 2), marks); - VMDumpConstants(func); - Printf("\nDisassembly:\n"); - VMDisasm(func->Code, func->NumCodeBytes / 4, func); + fprintf(dump, "\n%.*s %s %.*s", MAX(3, 38 - labellen / 2), marks, label, MAX(3, 38 - labellen / 2), marks); + VMDumpConstants(dump, func); + fprintf(dump, "\nDisassembly:\n"); + VMDisasm(dump, func->Code, func->NumCodeBytes / 4, func); #endif //if(i==6) I_Error("Poop"); } + fclose(dump); I_Error("Poop"); for (i = 0; i < PClass::m_Types.Size(); i++) diff --git a/src/zscript/vm.h b/src/zscript/vm.h index 9912637dc..95c32dd5c 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -812,7 +812,7 @@ void VMSelectEngine(EVMEngine engine); extern int (*VMExec)(VMFrameStack *stack, const VM_UBYTE *pc, VMReturn *ret, int numret); void VMFillParams(VMValue *params, VMFrame *callee, int numparam); -void VMDumpConstants(const VMScriptFunction *func); -void VMDisasm(const VM_UBYTE *code, int codesize, const VMScriptFunction *func); +void VMDumpConstants(FILE *out, const VMScriptFunction *func); +void VMDisasm(FILE *out, const VM_UBYTE *code, int codesize, const VMScriptFunction *func); #endif diff --git a/src/zscript/vmdisasm.cpp b/src/zscript/vmdisasm.cpp index 39f271084..7c85b5341 100644 --- a/src/zscript/vmdisasm.cpp +++ b/src/zscript/vmdisasm.cpp @@ -1,4 +1,5 @@ #include "vm.h" +#include "c_console.h" #define LI MODE_AI | MODE_BCJOINT | MODE_BCIMMS #define LKI MODE_AI | MODE_BCJOINT | MODE_BCKI @@ -99,66 +100,84 @@ const VMOpInfo OpInfo[NUM_OPS] = #define JMPOFS(x) ((*(VM_SWORD *)(x) >> 6) & ~3) #endif -static int print_reg(int col, int arg, int mode, int immshift, const VMScriptFunction *func); +static int print_reg(FILE *out, int col, int arg, int mode, int immshift, const VMScriptFunction *func); -void VMDumpConstants(const VMScriptFunction *func) +static int printf_wrapper(FILE *f, const char *fmt, ...) +{ + va_list argptr; + int count; + + va_start(argptr, fmt); + if (f == NULL) + { + count = VPrintf(PRINT_HIGH, fmt, argptr); + } + else + { + count = vfprintf(f, fmt, argptr); + } + va_end(argptr); + return count; +} + +void VMDumpConstants(FILE *out, const VMScriptFunction *func) { char tmp[21]; int i, j, k, kk; if (func->KonstD != NULL && func->NumKonstD != 0) { - Printf("\nConstant integers:\n"); + printf_wrapper(out, "\nConstant integers:\n"); kk = (func->NumKonstD + 3) / 4; for (i = 0; i < kk; ++i) { for (j = 0, k = i; j < 4 && k < func->NumKonstD; j++, k += kk) { mysnprintf(tmp, countof(tmp), "%3d. %d", k, func->KonstD[k]); - Printf("%-20s", tmp); + printf_wrapper(out, "%-20s", tmp); } - Printf("\n"); + printf_wrapper(out, "\n"); } } if (func->KonstF != NULL && func->NumKonstF != 0) { - Printf("\nConstant floats:\n"); + printf_wrapper(out, "\nConstant floats:\n"); kk = (func->NumKonstF + 3) / 4; for (i = 0; i < kk; ++i) { for (j = 0, k = i; j < 4 && k < func->NumKonstF; j++, k += kk) { mysnprintf(tmp, countof(tmp), "%3d. %.16f", k, func->KonstF[k]); - Printf("%-20s", tmp); + printf_wrapper(out, "%-20s", tmp); } - Printf("\n"); + printf_wrapper(out, "\n"); } } if (func->KonstA != NULL && func->NumKonstA != 0) { - Printf("\nConstant addresses:\n"); + printf_wrapper(out, "\nConstant addresses:\n"); kk = (func->NumKonstA + 3) / 4; for (i = 0; i < kk; ++i) { for (j = 0, k = i; j < 4 && k < func->NumKonstA; j++, k += kk) { mysnprintf(tmp, countof(tmp), "%3d. %p", k, func->KonstA[k]); - Printf("%-20s", tmp); + printf_wrapper(out, "%-20s", tmp); } - Printf("\n"); + printf_wrapper(out, "\n"); } } if (func->KonstS != NULL && func->NumKonstS != 0) { - Printf("\nConstant strings:\n"); + printf_wrapper(out, "\nConstant strings:\n"); for (i = 0; i < func->NumKonstS; ++i) { - Printf("%3d. %s\n", func->KonstS[k].GetChars()); + printf_wrapper(out, "%3d. %s\n", func->KonstS[k].GetChars()); } } } -void VMDisasm(const VM_UBYTE *code, int codesize, const VMScriptFunction *func) +void VMDisasm(FILE *out, const VM_UBYTE *code, int codesize, const VMScriptFunction *func) { const char *name; int col; @@ -186,13 +205,13 @@ void VMDisasm(const VM_UBYTE *code, int codesize, const VMScriptFunction *func) a &= CMP_CHECK | CMP_APPROX; } - Printf("%08x: %02x%02x%02x%02x %-8s", i, code[i], code[i+1], code[i+2], code[i+3], name); + printf_wrapper(out, "%08x: %02x%02x%02x%02x %-8s", i, code[i], code[i+1], code[i+2], code[i+3], name); col = 0; switch (code[i]) { case OP_JMP: case OP_TRY: - col = Printf("%08x", i + 4 + JMPOFS(&code[i])); + col = printf_wrapper(out, "%08x", i + 4 + JMPOFS(&code[i])); break; case OP_RET: @@ -200,15 +219,15 @@ void VMDisasm(const VM_UBYTE *code, int codesize, const VMScriptFunction *func) { if ((code[i+2] & REGT_FINAL) && a == 0) { - col = print_reg(0, *(VM_UHALF *)&code[i+2], MODE_PARAM, 16, func); + col = print_reg(out, 0, *(VM_UHALF *)&code[i+2], MODE_PARAM, 16, func); } else { - col = print_reg(0, a, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func); - col += print_reg(col, *(VM_UHALF *)&code[i+2], MODE_PARAM, 16, func); + col = print_reg(out, 0, a, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func); + col += print_reg(out, col, *(VM_UHALF *)&code[i+2], MODE_PARAM, 16, func); if (code[i+2] & REGT_FINAL) { - col += Printf(" [final]"); + col += printf_wrapper(out, " [final]"); } } } @@ -245,7 +264,7 @@ void VMDisasm(const VM_UBYTE *code, int codesize, const VMScriptFunction *func) break; } } - col = print_reg(0, a, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func); + col = print_reg(out, 0, a, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func); if ((mode & MODE_BCTYPE) == MODE_BCTHROW) { mode = (code[i+1] == 0) ? (MODE_BP | MODE_CUNUSED) : (MODE_BKP | MODE_CUNUSED); @@ -273,12 +292,12 @@ void VMDisasm(const VM_UBYTE *code, int codesize, const VMScriptFunction *func) } if ((mode & (MODE_BTYPE | MODE_CTYPE)) == MODE_BCJOINT) { - col += print_reg(col, *(VM_UHALF *)&code[i+2], (mode & MODE_BCTYPE) >> MODE_BCSHIFT, 16, func); + col += print_reg(out, col, *(VM_UHALF *)&code[i+2], (mode & MODE_BCTYPE) >> MODE_BCSHIFT, 16, func); } else { - col += print_reg(col, code[i+2], (mode & MODE_BTYPE) >> MODE_BSHIFT, 24, func); - col += print_reg(col, code[i+3], (mode & MODE_CTYPE) >> MODE_CSHIFT, 24, func); + col += print_reg(out, col, code[i+2], (mode & MODE_BTYPE) >> MODE_BSHIFT, 24, func); + col += print_reg(out, col, code[i+3], (mode & MODE_CTYPE) >> MODE_CSHIFT, 24, func); } break; } @@ -286,19 +305,19 @@ void VMDisasm(const VM_UBYTE *code, int codesize, const VMScriptFunction *func) { col = 30; } - Printf("%*c", 30 - col, ';'); + printf_wrapper(out, "%*c", 30 - col, ';'); if (code[i] == OP_JMP || code[i] == OP_TRY) { - Printf("%d\n", JMPOFS(&code[i]) >> 2); + printf_wrapper(out, "%d\n", JMPOFS(&code[i]) >> 2); } else { - Printf("%d,%d,%d\n", code[i+1], code[i+2], code[i+3]); + printf_wrapper(out, "%d,%d,%d\n", code[i+1], code[i+2], code[i+3]); } } } -static int print_reg(int col, int arg, int mode, int immshift, const VMScriptFunction *func) +static int print_reg(FILE *out, int col, int arg, int mode, int immshift, const VMScriptFunction *func) { if (mode == MODE_UNUSED) { @@ -306,57 +325,57 @@ static int print_reg(int col, int arg, int mode, int immshift, const VMScriptFun } if (col > 0) { - col = Printf(","); + col = printf_wrapper(out, ","); } switch(mode) { case MODE_I: - return col+Printf("d%d", arg); + return col+printf_wrapper(out, "d%d", arg); case MODE_F: - return col+Printf("f%d", arg); + return col+printf_wrapper(out, "f%d", arg); case MODE_S: - return col+Printf("s%d", arg); + return col+printf_wrapper(out, "s%d", arg); case MODE_P: - return col+Printf("a%d", arg); + return col+printf_wrapper(out, "a%d", arg); case MODE_V: - return col+Printf("v%d", arg); + return col+printf_wrapper(out, "v%d", arg); case MODE_KI: if (func != NULL) { - return col+Printf("%d", func->KonstD[arg]); + return col+printf_wrapper(out, "%d", func->KonstD[arg]); } - return Printf("kd%d", arg); + return printf_wrapper(out, "kd%d", arg); case MODE_KF: if (func != NULL) { - return col+Printf("%f", func->KonstF[arg]); + return col+printf_wrapper(out, "%f", func->KonstF[arg]); } - return col+Printf("kf%d", arg); + return col+printf_wrapper(out, "kf%d", arg); case MODE_KS: if (func != NULL) { - return col+Printf("\"%s\"", func->KonstS[arg].GetChars()); + return col+printf_wrapper(out, "\"%s\"", func->KonstS[arg].GetChars()); } - return col+Printf("ks%d", arg); + return col+printf_wrapper(out, "ks%d", arg); case MODE_KP: if (func != NULL) { - return col+Printf("%p", func->KonstA[arg]); + return col+printf_wrapper(out, "%p", func->KonstA[arg]); } - return col+Printf("ka%d", arg); + return col+printf_wrapper(out, "ka%d", arg); case MODE_KV: if (func != NULL) { - return col+Printf("(%f,%f,%f)", func->KonstF[arg], func->KonstF[arg+1], func->KonstF[arg+2]); + return col+printf_wrapper(out, "(%f,%f,%f)", func->KonstF[arg], func->KonstF[arg+1], func->KonstF[arg+2]); } - return col+Printf("kv%d", arg); + return col+printf_wrapper(out, "kv%d", arg); case MODE_IMMS: - return col+Printf("%d", (arg << immshift) >> immshift); + return col+printf_wrapper(out, "%d", (arg << immshift) >> immshift); case MODE_IMMZ: - return col+Printf("%d", arg); + return col+printf_wrapper(out, "%d", arg); case MODE_PARAM: { @@ -365,31 +384,31 @@ static int print_reg(int col, int arg, int mode, int immshift, const VMScriptFun switch (p.RegType & (REGT_TYPE | REGT_KONST | REGT_MULTIREG)) { case REGT_INT: - return col+Printf("d%d", p.RegNum); + return col+printf_wrapper(out, "d%d", p.RegNum); case REGT_FLOAT: - return col+Printf("f%d", p.RegNum); + return col+printf_wrapper(out, "f%d", p.RegNum); case REGT_STRING: - return col+Printf("s%d", p.RegNum); + return col+printf_wrapper(out, "s%d", p.RegNum); case REGT_POINTER: - return col+Printf("a%d", p.RegNum); + return col+printf_wrapper(out, "a%d", p.RegNum); case REGT_FLOAT | REGT_MULTIREG: - return col+Printf("v%d", p.RegNum); + return col+printf_wrapper(out, "v%d", p.RegNum); case REGT_INT | REGT_KONST: - return col+print_reg(0, p.RegNum, MODE_KI, 0, func); + return col+print_reg(out, 0, p.RegNum, MODE_KI, 0, func); case REGT_FLOAT | REGT_KONST: - return col+print_reg(0, p.RegNum, MODE_KF, 0, func); + return col+print_reg(out, 0, p.RegNum, MODE_KF, 0, func); case REGT_STRING | REGT_KONST: - return col+print_reg(0, p.RegNum, MODE_KS, 0, func); + return col+print_reg(out, 0, p.RegNum, MODE_KS, 0, func); case REGT_POINTER | REGT_KONST: - return col+print_reg(0, p.RegNum, MODE_KP, 0, func); + return col+print_reg(out, 0, p.RegNum, MODE_KP, 0, func); case REGT_FLOAT | REGT_MULTIREG | REGT_KONST: - return col+print_reg(0, p.RegNum, MODE_KV, 0, func); + return col+print_reg(out, 0, p.RegNum, MODE_KV, 0, func); default: if (p.RegType == REGT_NIL) { - return col+Printf("nil"); + return col+printf_wrapper(out, "nil"); } - return col+Printf("param[t=%d,%c,%c,n=%d]", + return col+printf_wrapper(out, "param[t=%d,%c,%c,n=%d]", p.RegType & REGT_TYPE, p.RegType & REGT_KONST ? 'k' : 'r', p.RegType & REGT_MULTIREG ? 'm' : 's', @@ -398,7 +417,7 @@ static int print_reg(int col, int arg, int mode, int immshift, const VMScriptFun } default: - return col+Printf("$%d", arg); + return col+printf_wrapper(out, "$%d", arg); } return col; } From 126c7381168b1c6b8f553611d6968983a027e9d1 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Thu, 15 Oct 2009 21:59:37 +0000 Subject: [PATCH 012/232] - Added PARAMI for the common case of passing an integer constant to a function. - Made FxParameter::Emit free its operand's register. SVN r1918 (scripting) --- src/thingdef/thingdef_expression.cpp | 114 ++++++++++----------------- src/zscript/vmbuilder.cpp | 4 + src/zscript/vmdisasm.cpp | 6 ++ src/zscript/vmexec.cpp | 2 + src/zscript/vmexec.h | 7 ++ src/zscript/vmops.h | 3 +- 6 files changed, 61 insertions(+), 75 deletions(-) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 34f4a4080..c40ba766f 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -334,6 +334,7 @@ FxParameter::FxParameter(FxExpression *operand) : FxExpression(operand->ScriptPosition) { Operand = operand; + ValueType = operand->ValueType; } //========================================================================== @@ -357,9 +358,23 @@ FxExpression *FxParameter::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); SAFE_RESOLVE(Operand, ctx); + ValueType = Operand->ValueType; return this; } +static void EmitConstantInt(VMFunctionBuilder *build, int val) +{ + // If it fits in 24 bits, use PARAMI instead of PARAM. + if ((val << 8) >> 8) + { + build->Emit(OP_PARAMI, val); + } + else + { + build->Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, build->GetConstantInt(val)); + } +} + ExpEmit FxParameter::Emit(VMFunctionBuilder *build) { if (Operand->isConstant()) @@ -367,7 +382,7 @@ ExpEmit FxParameter::Emit(VMFunctionBuilder *build) ExpVal val = Operand->EvalExpression(NULL); if (val.Type == VAL_Int || val.Type == VAL_Sound || val.Type == VAL_Name || val.Type == VAL_Color) { - build->Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, build->GetConstantInt(val.Int)); + EmitConstantInt(build, val.Int); } else if (val.Type == VAL_Float) { @@ -398,6 +413,7 @@ ExpEmit FxParameter::Emit(VMFunctionBuilder *build) else { build->Emit(OP_PARAM, 0, where.RegType, where.RegNum); + build->FreeReg(where.RegType, where.RegNum); } } return ExpEmit(); @@ -2366,8 +2382,8 @@ FxRandom::FxRandom(FRandom * r, FxExpression *mi, FxExpression *ma, const FScrip { if (mi != NULL && ma != NULL) { - min = new FxIntCast(mi); - max = new FxIntCast(ma); + min = new FxParameter(new FxIntCast(mi)); + max = new FxParameter(new FxIntCast(ma)); } else min = max = NULL; rng = r; @@ -2397,17 +2413,11 @@ FxExpression *FxRandom::Resolve(FCompileContext &ctx) CHECKRESOLVED(); if (min && max) { - if (min->ValueType != VAL_Int) - { - min = new FxIntCast(min); - } - if (max->ValueType != VAL_Int) - { - max = new FxIntCast(max); - } RESOLVE(min, ctx); RESOLVE(max, ctx); ABORT(min && max); + assert(min->ValueType == VAL_Int); + assert(max->ValueType == VAL_Int); } return this; }; @@ -2489,28 +2499,8 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build) build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); if (min != NULL && max != NULL) { - ExpEmit op = min->Emit(build); - assert(op.RegType == REGT_INT); - if (op.Konst) - { - build->Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, op.RegNum); - } - else - { - build->FreeReg(REGT_INT, op.RegNum); - build->Emit(OP_PARAM, 0, REGT_INT, op.RegNum); - } - op = max->Emit(build); - assert(op.RegType == REGT_INT); - if (op.Konst) - { - build->Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, op.RegNum); - } - else - { - build->FreeReg(REGT_INT, op.RegNum); - build->Emit(OP_PARAM, 0, REGT_INT, op.RegNum); - } + min->Emit(build); + max->Emit(build); build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); } else @@ -2532,8 +2522,8 @@ FxFRandom::FxFRandom(FRandom *r, FxExpression *mi, FxExpression *ma, const FScri { if (mi != NULL && ma != NULL) { - min = mi; - max = ma; + min = new FxParameter(new FxFloatCast(mi)); + max = new FxParameter(new FxFloatCast(ma)); } } @@ -2614,28 +2604,8 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); if (min != NULL && max != NULL) { - ExpEmit op = min->Emit(build); - assert(op.RegType == REGT_FLOAT); - if (op.Konst) - { - build->Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, op.RegNum); - } - else - { - build->FreeReg(REGT_FLOAT, op.RegNum); - build->Emit(OP_PARAM, 0, REGT_FLOAT, op.RegNum); - } - op = max->Emit(build); - assert(op.RegType == REGT_FLOAT); - if (op.Konst) - { - build->Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, op.RegNum); - } - else - { - build->FreeReg(REGT_FLOAT, op.RegNum); - build->Emit(OP_PARAM, 0, REGT_FLOAT, op.RegNum); - } + min->Emit(build); + max->Emit(build); build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); } else @@ -2659,6 +2629,7 @@ FxRandom2::FxRandom2(FRandom *r, FxExpression *m, const FScriptPosition &pos) rng = r; if (m) mask = new FxIntCast(m); else mask = new FxConstant(-1, pos); + mask = new FxParameter(mask); ValueType = VAL_Int; } @@ -2721,17 +2692,7 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) callfunc = ((PSymbolVMFunction *)sym)->Function; build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); - ExpEmit op = mask->Emit(build); - assert(op.RegType == REGT_INT); - if (op.Konst) - { - build->Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, op.RegNum); - } - else - { - build->FreeReg(REGT_INT, op.RegNum); - build->Emit(OP_PARAM, 0, REGT_INT, op.RegNum); - } + mask->Emit(build); build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1); ExpEmit out(build, REGT_INT); build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum); @@ -3513,17 +3474,22 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) assert(Self == NULL); unsigned i = 0; - build->Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, build->GetConstantInt(Special)); // pass special number + build->Emit(OP_PARAMI, Special); // pass special number build->Emit(OP_PARAM, 0, REGT_POINTER, 0); // pass self if (ArgList != NULL) { for (; i < ArgList->Size(); ++i) { - ExpEmit arg((*ArgList)[i]->Emit(build)); - assert(arg.RegType == REGT_INT); - build->Emit(OP_PARAM, 0, arg.RegType | (arg.Konst ? REGT_KONST : 0), arg.RegNum); - if (!arg.Konst) + FxExpression *argex = (*ArgList)[i]; + assert(argex->ValueType == VAL_Int); + if (argex->isConstant()) { + EmitConstantInt(build, argex->EvalExpression(NULL).GetInt()); + } + else + { + ExpEmit arg(argex->Emit(build)); + build->Emit(OP_PARAM, 0, arg.RegType, arg.RegNum); build->FreeReg(arg.RegType, arg.RegNum); } } @@ -3991,7 +3957,7 @@ ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build) build->Emit(OP_PARAM, 0, REGT_POINTER, 0); // pass self for (unsigned i = 0; i < names.Size(); ++i) { - build->Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, build->GetConstantInt(names[i])); + EmitConstantInt(build, names[i]); } // Find the DecoFindMultiNameState function. If not found, create it and install it diff --git a/src/zscript/vmbuilder.cpp b/src/zscript/vmbuilder.cpp index 114f27d8e..450190ddf 100644 --- a/src/zscript/vmbuilder.cpp +++ b/src/zscript/vmbuilder.cpp @@ -465,6 +465,10 @@ size_t VMFunctionBuilder::Emit(int opcode, int opabc) #else *(VM_UWORD *)&Code[loc] = opcode | (opabc << 8); #endif + if (opcode == OP_PARAMI) + { + ParamChange(1); + } return loc / 4; } diff --git a/src/zscript/vmdisasm.cpp b/src/zscript/vmdisasm.cpp index 7c85b5341..108f4b726 100644 --- a/src/zscript/vmdisasm.cpp +++ b/src/zscript/vmdisasm.cpp @@ -95,8 +95,10 @@ const VMOpInfo OpInfo[NUM_OPS] = }; #ifdef WORDS_BIGENDIAN +#define ABCs(x) ((*(VM_SWORD *)(x) << 8) >> 8) #define JMPOFS(x) ((*(VM_SWORD *)(x) << 8) >> 6) #else +#define ABCs(x) (*(VM_SWORD *)(x) >> 8) #define JMPOFS(x) ((*(VM_SWORD *)(x) >> 6) & ~3) #endif @@ -214,6 +216,10 @@ void VMDisasm(FILE *out, const VM_UBYTE *code, int codesize, const VMScriptFunct col = printf_wrapper(out, "%08x", i + 4 + JMPOFS(&code[i])); break; + case OP_PARAMI: + col = printf_wrapper(out, "%d", i + 4 + ABCs(&code[i])); + break; + case OP_RET: if (code[i+2] != REGT_NIL) { diff --git a/src/zscript/vmexec.cpp b/src/zscript/vmexec.cpp index 8835afcc8..6ef11c29b 100644 --- a/src/zscript/vmexec.cpp +++ b/src/zscript/vmexec.cpp @@ -25,8 +25,10 @@ #define BCs (*(VM_SHALF *)(pc - 2)) #ifdef WORDS_BIGENDIAN +#define ABCs ((*(VM_SWORD *)(pc - 4) << 8) >> 8) #define JMPOFS(x) ((*(VM_SWORD *)(x) << 8) >> 6) #else +#define ABCs (*(VM_SWORD *)(pc - 4) >> 8) #define JMPOFS(x) ((*(VM_SWORD *)(x) >> 6) & ~3) #endif diff --git a/src/zscript/vmexec.h b/src/zscript/vmexec.h index e300e6644..f8da2f291 100644 --- a/src/zscript/vmexec.h +++ b/src/zscript/vmexec.h @@ -395,6 +395,13 @@ begin: assert(*pc == OP_JMP); pc += (1 + *((VM_SHALF *)pc + 1)) << 2; NEXTOP; + OP(PARAMI): + assert(f->NumParam < sfunc->MaxParam); + { + VMValue *param = ®.param[f->NumParam++]; + ::new(param) VMValue(ABCs); + } + NEXTOP; OP(PARAM): assert(f->NumParam < sfunc->MaxParam); { diff --git a/src/zscript/vmops.h b/src/zscript/vmops.h index 00c6f5d13..20178dfb0 100644 --- a/src/zscript/vmops.h +++ b/src/zscript/vmops.h @@ -74,6 +74,7 @@ xx(TEST, test, RII16), // if (dA != BC) then pc++ xx(JMP, jmp, I24), // pc += ABC -- The ABC fields contain a signed 24-bit offset. xx(IJMP, ijmp, RII16), // pc += dA + BC -- BC is a signed offset. The target instruction must be a JMP. xx(PARAM, param, __BCP), // push parameter encoded in BC for function call (B=regtype, C=regnum) +xx(PARAMI, parami, I24), // push immediate, signed integer for function call xx(CALL, call, RPI8I8), // Call function pkA with parameter count B and expected result count C xx(CALL_K, call, KPI8I8), xx(RESULT, result, __BCP), // Result should go in register encoded in BC (in caller, after CALL) @@ -106,7 +107,7 @@ xx(SRA_RI, sra, RIRII8), xx(SRA_KR, sra, RIKIRI), xx(ADD_RR, add, RIRIRI), // dA = dB + dkC xx(ADD_RK, add, RIRIKI), -xx(ADDI, add, RIRIIs), // dA = dB + C -- C is a signed 8-bit constant +xx(ADDI, addi, RIRIIs), // dA = dB + C -- C is a signed 8-bit constant xx(SUB_RR, sub, RIRIRI), // dA = dkB - dkC xx(SUB_RK, sub, RIRIKI), xx(SUB_KR, sub, RIKIRI), From 3cbac657d6ebb7c00740b4fe45d720f6a22fbf9b Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Thu, 15 Oct 2009 22:15:55 +0000 Subject: [PATCH 013/232] - Added type coercion for action function parameters. - I add PARAMI, and then I don't even do it right... SVN r1919 (scripting) --- src/thingdef/thingdef.cpp | 2 +- src/thingdef/thingdef_expression.cpp | 2 +- src/thingdef/thingdef_parse.cpp | 15 +++++++++++++++ src/zscript/vmdisasm.cpp | 2 +- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index b8ae5fc8f..918768215 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -303,7 +303,7 @@ static void FinishThingdef() VMScriptFunction *func = buildit.MakeFunction(); #if 1 const char *marks = "======================================================="; - char label[40]; + char label[64]; int labellen = mysnprintf(label, countof(label), "Function %s.States[%d] (*%d)", tcall->ActorInfo->Class->TypeName.GetChars(), tcall->FirstState, tcall->NumStates); diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index c40ba766f..f8941c822 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -365,7 +365,7 @@ FxExpression *FxParameter::Resolve(FCompileContext& ctx) static void EmitConstantInt(VMFunctionBuilder *build, int val) { // If it fits in 24 bits, use PARAMI instead of PARAM. - if ((val << 8) >> 8) + if (((val << 8) >> 8) == val) { build->Emit(OP_PARAMI, val); } diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index eb68a6d27..02fb125d6 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -151,6 +151,21 @@ FxExpression *ParseParameter(FScanner &sc, PClass *cls, char type, bool constant { sc.ScriptError("Default parameter must be constant."); } + // Do automatic coercion between ints and floats. + if (type == 'x' || type == 'X') + { + if (x->ValueType != VAL_Int) + { + x = new FxIntCast(x); + } + } + else + { + if (x->ValueType != VAL_Float) + { + x = new FxFloatCast(x); + } + } break; default: diff --git a/src/zscript/vmdisasm.cpp b/src/zscript/vmdisasm.cpp index 108f4b726..0864e881b 100644 --- a/src/zscript/vmdisasm.cpp +++ b/src/zscript/vmdisasm.cpp @@ -217,7 +217,7 @@ void VMDisasm(FILE *out, const VM_UBYTE *code, int codesize, const VMScriptFunct break; case OP_PARAMI: - col = printf_wrapper(out, "%d", i + 4 + ABCs(&code[i])); + col = printf_wrapper(out, "%d", ABCs(&code[i])); break; case OP_RET: From c424c61ffc2db411b94f84f4402e9b2a517d9df2 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Thu, 15 Oct 2009 23:11:54 +0000 Subject: [PATCH 014/232] - Added fixed registers that won't be freed automatically, so that parameters can actually be used. In the end, all temporaries should be assigned to unique virtual registers, and a register allocator can alias them to real registers, but as long as we don't do any CSE, this is good enough for now. SVN r1920 (scripting) --- src/thingdef/thingdef.cpp | 6 ++ src/thingdef/thingdef_exp.h | 9 +-- src/thingdef/thingdef_expression.cpp | 98 ++++++++++++---------------- src/zscript/vmbuilder.h | 3 - 4 files changed, 53 insertions(+), 63 deletions(-) diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 918768215..29e23a039 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -292,6 +292,10 @@ static void FinishThingdef() tcall->Parameters[j]->Resolve(ctx); } VMFunctionBuilder buildit; + // Allocate registers used to pass parameters in. + // self, stateowner, state, statecalldata (all are pointers) + buildit.Registers[REGT_POINTER].Get(4); + // Emit code for action parameters. for (j = 0; j < tcall->Parameters.Size(); ++j) { FxExpression *p = /*new FxParameter*/(tcall->Parameters[j]); @@ -308,6 +312,8 @@ static void FinishThingdef() tcall->ActorInfo->Class->TypeName.GetChars(), tcall->FirstState, tcall->NumStates); fprintf(dump, "\n%.*s %s %.*s", MAX(3, 38 - labellen / 2), marks, label, MAX(3, 38 - labellen / 2), marks); + fprintf(dump, "\nInteger regs: %-3d Float regs: %-3d Address regs: %-3d String regs: %-3d\nStack size: %d\n", + func->NumRegD, func->NumRegF, func->NumRegA, func->NumRegS, func->MaxParam); VMDumpConstants(dump, func); fprintf(dump, "\nDisassembly:\n"); VMDisasm(dump, func->Code, func->NumCodeBytes / 4, func); diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 53c719de7..719c1c66f 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -146,12 +146,13 @@ struct ExpVal struct ExpEmit { - ExpEmit() : RegNum(0), RegType(REGT_NIL) {} - ExpEmit(int reg, int type) : RegNum(reg), RegType(type) {} - ExpEmit(int reg, int type, bool konst) : RegNum(reg), RegType(type), Konst(konst) {} + ExpEmit() : RegNum(0), RegType(REGT_NIL), Konst(false), Fixed(false) {} + ExpEmit(int reg, int type) : RegNum(reg), RegType(type), Konst(false), Fixed(false) {} + ExpEmit(int reg, int type, bool konst) : RegNum(reg), RegType(type), Konst(konst), Fixed(false) {} ExpEmit(VMFunctionBuilder *build, int type); + void Free(VMFunctionBuilder *build); - BYTE RegNum, RegType, Konst; + BYTE RegNum, RegType, Konst:1, Fixed:1; }; //========================================================================== diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index f8941c822..a4f076ae2 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -79,10 +79,18 @@ DEFINE_MEMBER_VARIABLE(Score, AActor) DEFINE_MEMBER_VARIABLE(uservar, AActor) ExpEmit::ExpEmit(VMFunctionBuilder *build, int type) -: RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false) +: RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false), Fixed(false) { } +void ExpEmit::Free(VMFunctionBuilder *build) +{ + if (!Fixed && !Konst) + { + build->Registers[RegType].Return(RegNum, 1); + } +} + //========================================================================== // // EvalExpression @@ -413,7 +421,7 @@ ExpEmit FxParameter::Emit(VMFunctionBuilder *build) else { build->Emit(OP_PARAM, 0, where.RegType, where.RegNum); - build->FreeReg(where.RegType, where.RegNum); + where.Free(build); } } return ExpEmit(); @@ -664,7 +672,7 @@ ExpEmit FxFloatCast::Emit(VMFunctionBuilder *build) ExpEmit from = basex->Emit(build); assert(!from.Konst); assert(basex->ValueType == VAL_Int); - build->FreeReg(from.RegType, from.RegNum); + from.Free(build); ExpEmit to(build, REGT_FLOAT); build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_I2F); return to; @@ -991,9 +999,9 @@ ExpVal FxUnaryNotBoolean::EvalExpression (AActor *self) ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build) { ExpEmit from = Operand->Emit(build); - assert(from.Konst != 0); + assert(!from.Konst); ExpEmit to(build, REGT_INT); - build->FreeReg(from.RegType, from.RegNum); + from.Free(build); // Preload result with 0. build->Emit(OP_LI, to.RegNum, 0, 0); @@ -1207,11 +1215,8 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build) swap(op1, op2); } assert(!op1.Konst); - build->FreeReg(op1.RegType, op1.RegNum); - if (!op2.Konst) - { - build->FreeReg(op2.RegType, op2.RegNum); - } + op1.Free(build); + op2.Free(build); if (ValueType == VAL_Float) { assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); @@ -1232,14 +1237,8 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build) { // Subtraction is not commutative, so either side may be constant (but not both). assert(!op1.Konst || !op2.Konst); - if (!op1.Konst) - { - build->FreeReg(op1.RegType, op1.RegNum); - } - if (!op2.Konst) - { - build->FreeReg(op2.RegType, op2.RegNum); - } + op1.Free(build); + op2.Free(build); if (ValueType == VAL_Float) { assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); @@ -1397,11 +1396,8 @@ ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build) swap(op1, op2); } assert(!op1.Konst); - build->FreeReg(op1.RegType, op1.RegNum); - if (!op2.Konst) - { - build->FreeReg(op2.RegType, op2.RegNum); - } + op1.Free(build); + op2.Free(build); if (ValueType == VAL_Float) { assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); @@ -1423,14 +1419,8 @@ ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build) // Division is not commutative, so either side may be constant (but not both). assert(!op1.Konst || !op2.Konst); assert(Operator == '%' || Operator == '/'); - if (!op1.Konst) - { - build->FreeReg(op1.RegType, op1.RegNum); - } - if (!op2.Konst) - { - build->FreeReg(op2.RegType, op2.RegNum); - } + op1.Free(build); + op2.Free(build); if (ValueType == VAL_Float) { assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); @@ -1574,7 +1564,7 @@ ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build) } else { - build->FreeReg(op2.RegType, op2.RegNum); + op2.Free(build); } if (op1.Konst) { @@ -1582,7 +1572,7 @@ ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build) } else { - build->FreeReg(op1.RegType, op1.RegNum); + op1.Free(build); } ExpEmit to(build, op1.RegType); @@ -1715,10 +1705,10 @@ ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build) instr = op1.RegType == REGT_INT ? OP_EQ_R : op1.RegType == REGT_FLOAT ? OP_EQF_R : OP_EQA_R; - build->FreeReg(op1.RegType, op1.RegNum); + op1.Free(build); if (!op2.Konst) { - build->FreeReg(op2.RegType, op2.RegNum); + op2.Free(build); } else { @@ -1863,7 +1853,7 @@ ExpEmit FxBinaryInt::Emit(VMFunctionBuilder *build) { op2 = right->Emit(build); assert(!op2.Konst); - build->FreeReg(op2.RegType, op2.RegNum); + op2.Free(build); rop = op2.RegNum; } } @@ -1876,14 +1866,11 @@ ExpEmit FxBinaryInt::Emit(VMFunctionBuilder *build) } assert(!op1.Konst); rop = op2.RegNum; - if (!op2.Konst) - { - build->FreeReg(op2.RegType, op2.RegNum); - } + op2.Free(build); } if (!op1.Konst) { - build->FreeReg(op1.RegType, op1.RegNum); + op1.Free(build); if (!op2.Konst) { instr = InstrMap[index][0]; @@ -2058,7 +2045,7 @@ ExpEmit FxBinaryLogical::Emit(VMFunctionBuilder *build) ExpEmit op1 = left->Emit(build); assert(!op1.Konst); int zero = build->GetConstantInt(0); - build->FreeReg(op1.RegType, op1.RegNum); + op1.Free(build); if (Operator == TK_AndAnd) { @@ -2069,7 +2056,7 @@ ExpEmit FxBinaryLogical::Emit(VMFunctionBuilder *build) // Evaluate op2. ExpEmit op2 = right->Emit(build); assert(!op2.Konst); - build->FreeReg(op2.RegType, op2.RegNum); + op2.Free(build); ExpEmit to(build, REGT_INT); build->Emit(OP_EQ_K, 0, op2.RegNum, zero); @@ -2090,7 +2077,7 @@ ExpEmit FxBinaryLogical::Emit(VMFunctionBuilder *build) // Evaluate op2. ExpEmit op2 = right->Emit(build); assert(!op2.Konst); - build->FreeReg(op2.RegType, op2.RegNum); + op2.Free(build); ExpEmit to(build, REGT_INT); build->Emit(OP_EQ_K, 1, op2.RegNum, zero); @@ -2250,7 +2237,7 @@ ExpEmit FxConditional::Emit(VMFunctionBuilder *build) // Move result from the register returned by "false" to the one // returned by "true" so that only one register is returned by // this tree. - build->FreeReg(falseop.RegType, falseop.RegNum); + falseop.Free(build); if (falseop.RegType == REGT_INT) { build->Emit(OP_MOVE, out.RegNum, falseop.RegNum, 0); @@ -2848,7 +2835,9 @@ ExpVal FxSelf::EvalExpression (AActor *self) ExpEmit FxSelf::Emit(VMFunctionBuilder *build) { // self is always the first pointer passed to the function; - return ExpEmit(0, REGT_POINTER); + ExpEmit me(0, REGT_POINTER); + me.Fixed = true; + return me; } //========================================================================== @@ -3059,10 +3048,7 @@ ExpEmit FxClassMember::Emit(VMFunctionBuilder *build) { return obj; } - if (!obj.Konst) - { - build->FreeReg(obj.RegType, obj.RegNum); - } + obj.Free(build); ExpEmit out(build, REGT_POINTER); build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, build->GetConstantInt((int)membervar->offset)); return out; @@ -3117,7 +3103,7 @@ ExpEmit FxClassMember::Emit(VMFunctionBuilder *build) build->Emit(OP_LW, tmp.RegNum, obj.RegNum, offsetreg); build->Emit(OP_CAST, loc.RegNum, tmp.RegNum, CAST_I2F); build->Emit(OP_MULF_RK, loc.RegNum, loc.RegNum, build->GetConstantFloat(90.0 / ANGLE_90)); - build->FreeReg(tmp.RegType, tmp.RegNum); + tmp.Free(build); break; case VAL_Object: @@ -3129,7 +3115,7 @@ ExpEmit FxClassMember::Emit(VMFunctionBuilder *build) default: assert(0); } - build->FreeReg(obj.RegType, obj.RegNum); + obj.Free(build); return loc; } @@ -3271,9 +3257,9 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) build->Emit(OP_SLL_RI, indexv.RegNum, indexv.RegNum, 2); build->Emit(OP_BOUND, indexv.RegNum, Array->ValueType.size); build->Emit(OP_LW_R, dest.RegNum, start.RegNum, indexv.RegNum); - build->FreeReg(indexv.RegType, indexv.RegNum); + indexv.Free(build); } - build->FreeReg(start.RegType, start.RegNum); + start.Free(build); return dest; } @@ -3490,7 +3476,7 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) { ExpEmit arg(argex->Emit(build)); build->Emit(OP_PARAM, 0, arg.RegType, arg.RegNum); - build->FreeReg(arg.RegType, arg.RegNum); + arg.Free(build); } } } @@ -3772,7 +3758,7 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build) build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1); build->Emit(OP_RESULT, 0, REGT_POINTER, dest.RegNum); - build->FreeReg(clsname.RegType, clsname.RegNum); + clsname.Free(build); return dest; } diff --git a/src/zscript/vmbuilder.h b/src/zscript/vmbuilder.h index e09b8bfe8..328377f67 100644 --- a/src/zscript/vmbuilder.h +++ b/src/zscript/vmbuilder.h @@ -50,9 +50,6 @@ public: // Track available registers. RegAvailability Registers[4]; - // Free a register. - void FreeReg(int regtype, int regnum) { Registers[regtype].Return(regnum, 1); } - private: struct AddrKonst { From e5ef25591d98322cb56c99e54158535fa6bbfbc6 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 17 Oct 2009 00:33:23 +0000 Subject: [PATCH 015/232] - Use a union, rather than pointer aliasing, to access the parts of a VM instruction. SVN r1922 (scripting) --- src/autostart.cpp | 10 ++-- src/info.cpp | 4 +- src/thingdef/thingdef.cpp | 2 +- src/zscript/vm.h | 46 +++++++++++++++--- src/zscript/vmbuilder.cpp | 50 +++++++++----------- src/zscript/vmbuilder.h | 2 +- src/zscript/vmdisasm.cpp | 98 +++++++++++++++++++-------------------- src/zscript/vmexec.cpp | 32 ++++++------- src/zscript/vmexec.h | 72 ++++++++++++++-------------- src/zscript/vmframe.cpp | 9 ++-- 10 files changed, 171 insertions(+), 154 deletions(-) diff --git a/src/autostart.cpp b/src/autostart.cpp index 3822bafc1..7babed907 100644 --- a/src/autostart.cpp +++ b/src/autostart.cpp @@ -98,11 +98,11 @@ __declspec(allocate(".yreg$a")) void *const YRegHead = 0; // (There are linker scripts, but that apparently involves extracting the // default script from ld and then modifying it.) -void *ARegHead const __attribute__((section(SECTION_AREG))) = 0; -void *CRegHead const __attribute__((section(SECTION_CREG))) = 0; -void *GRegHead const __attribute__((section(SECTION_GREG))) = 0; -void *MRegHead const __attribute__((section(SECTION_MREG))) = 0; -void *YRegHead const __attribute__((section(SECTION_YREG))) = 0; +void *const ARegHead __attribute__((section(SECTION_AREG))) = 0; +void *const CRegHead __attribute__((section(SECTION_CREG))) = 0; +void *const GRegHead __attribute__((section(SECTION_GREG))) = 0; +void *const MRegHead __attribute__((section(SECTION_MREG))) = 0; +void *const YRegHead __attribute__((section(SECTION_YREG))) = 0; #else diff --git a/src/info.cpp b/src/info.cpp index 8f36ffac4..4d56875e3 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -94,11 +94,11 @@ void FState::SetAction(PSymbolActionFunction *func, bool setdefaultparams) // Create a function for this state. VMScriptFunction *vmfunc = new VMScriptFunction; - VM_UBYTE *code = vmfunc->AllocCode(sizeof(codetemplate)/VM_OPSIZE); + VMOP *code = vmfunc->AllocCode(sizeof(codetemplate)/sizeof(VMOP)); memcpy(code, codetemplate, sizeof(codetemplate)); FVoidObj *konsta = vmfunc->AllocKonstA(2); VM_ATAG *atag = vmfunc->KonstATags(); - konsta[0].v = func->Function; + konsta[0].v = (void *)func->Function; konsta[1].o = callfunc; atag[0] = ATAG_GENERIC; atag[1] = ATAG_OBJECT; diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 29e23a039..605f161e5 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -316,7 +316,7 @@ static void FinishThingdef() func->NumRegD, func->NumRegF, func->NumRegA, func->NumRegS, func->MaxParam); VMDumpConstants(dump, func); fprintf(dump, "\nDisassembly:\n"); - VMDisasm(dump, func->Code, func->NumCodeBytes / 4, func); + VMDisasm(dump, func->Code, func->CodeSize, func); #endif //if(i==6) I_Error("Poop"); } diff --git a/src/zscript/vm.h b/src/zscript/vm.h index 95c32dd5c..16987ed72 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -17,7 +17,41 @@ typedef signed int VM_SWORD; typedef VM_UBYTE VM_ATAG; #define VM_EPSILON (1/1024.0) -#define VM_OPSIZE 4 // Number of bytes used by one opcode + +union VMOP +{ + struct + { + VM_UBYTE op, a, b, c; + }; + struct + { + VM_SBYTE pad0, as, bs, cs; + }; + struct + { + VM_SWORD pad1:8, i24:24; + }; + struct + { + VM_SWORD pad2:16, i16:16; + }; + struct + { + VM_UHALF pad3, i16u; + }; + VM_UWORD word; + + // Interesting fact: VC++ produces better code for i16 when it's defined + // as a bitfield than when it's defined as two discrete units. + // Compare: + // mov eax,dword ptr [op] ; As two discrete units + // shr eax,10h + // movsx eax,ax + // versus: + // mov eax,dword ptr [op] ; As a bitfield + // sar eax,10h +}; enum { @@ -685,7 +719,7 @@ public: VMScriptFunction(); ~VMScriptFunction(); size_t PropagateMark(); - VM_UBYTE *AllocCode(int numops); + VMOP *AllocCode(int numops); int *AllocKonstD(int numkonst); double *AllocKonstF(int numkonst); FString *AllocKonstS(int numkonst); @@ -694,13 +728,13 @@ public: VM_ATAG *KonstATags() { return (VM_UBYTE *)(KonstA + NumKonstA); } const VM_ATAG *KonstATags() const { return (VM_UBYTE *)(KonstA + NumKonstA); } - VM_UBYTE *Code; + VMOP *Code; int *KonstD; double *KonstF; FString *KonstS; FVoidObj *KonstA; int ExtraSpace; - int NumCodeBytes; + int CodeSize; // Size of code in instructions (not bytes) VM_UBYTE NumRegD; VM_UBYTE NumRegF; VM_UBYTE NumRegS; @@ -809,10 +843,10 @@ enum EVMEngine }; void VMSelectEngine(EVMEngine engine); -extern int (*VMExec)(VMFrameStack *stack, const VM_UBYTE *pc, VMReturn *ret, int numret); +extern int (*VMExec)(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret); void VMFillParams(VMValue *params, VMFrame *callee, int numparam); void VMDumpConstants(FILE *out, const VMScriptFunction *func); -void VMDisasm(FILE *out, const VM_UBYTE *code, int codesize, const VMScriptFunction *func); +void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction *func); #endif diff --git a/src/zscript/vmbuilder.cpp b/src/zscript/vmbuilder.cpp index 450190ddf..b681c3d66 100644 --- a/src/zscript/vmbuilder.cpp +++ b/src/zscript/vmbuilder.cpp @@ -39,7 +39,7 @@ VMScriptFunction *VMFunctionBuilder::MakeFunction() VMScriptFunction *func = new VMScriptFunction; // Copy code block. - memcpy(func->AllocCode(Code.Size()), &Code[0], Code.Size()); + memcpy(func->AllocCode(Code.Size()), &Code[0], Code.Size() * sizeof(VMOP)); // Create constant tables. if (NumIntConstants > 0) @@ -425,12 +425,6 @@ size_t VMFunctionBuilder::Emit(int opcode, int opa, int opb, int opc) assert(opa >= 0 && opa <= 255); assert(opb >= 0 && opb <= 255); assert(opc >= 0 && opc <= 255); - size_t loc = Code.Reserve(4); - VM_UBYTE *code = &Code[loc]; - code[0] = opcode; - code[1] = opa; - code[2] = opb; - code[3] = opc; if (opcode == OP_PARAM) { ParamChange(1); @@ -439,7 +433,12 @@ size_t VMFunctionBuilder::Emit(int opcode, int opa, int opb, int opc) { ParamChange(-opb); } - return loc / 4; + VMOP op; + op.op = opcode; + op.a = opa; + op.b = opb; + op.c = opc; + return Code.Push(op); } size_t VMFunctionBuilder::Emit(int opcode, int opa, VM_SHALF opbc) @@ -447,29 +446,25 @@ size_t VMFunctionBuilder::Emit(int opcode, int opa, VM_SHALF opbc) assert(opcode >= 0 && opcode < NUM_OPS); assert(opa >= 0 && opa <= 255); assert(opbc >= -32768 && opbc <= 32767); - size_t loc = Code.Reserve(4); - VM_UBYTE *code = &Code[loc]; - code[0] = opcode; - code[1] = opa; - *(VM_SHALF *)&code[2] = opbc; - return loc / 4; + VMOP op; + op.op = opcode; + op.a = opa; + op.i16 = opbc; + return Code.Push(op); } size_t VMFunctionBuilder::Emit(int opcode, int opabc) { assert(opcode >= 0 && opcode < NUM_OPS); assert(opabc >= -(1 << 23) && opabc <= (1 << 24) - 1); - size_t loc = Code.Reserve(4); -#ifdef __BIG_ENDIAN__ - *(VM_UWORD *)&Code[loc] = (opabc & 0xFFFFFF) | (opcode << 24); -#else - *(VM_UWORD *)&Code[loc] = opcode | (opabc << 8); -#endif if (opcode == OP_PARAMI) { ParamChange(1); } - return loc / 4; + VMOP op; + op.op = opcode; + op.i24 = opabc; + return Code.Push(op); } //========================================================================== @@ -504,14 +499,11 @@ size_t VMFunctionBuilder::EmitLoadInt(int regnum, int value) void VMFunctionBuilder::Backpatch(size_t loc, size_t target) { - assert(loc < Code.Size() / 4); + assert(loc < Code.Size()); int offset = int(target - loc - 1); - assert(offset >= -(1 << 24) && offset <= (1 << 24) - 1); -#ifdef __BIG_ENDIAN__ - *(VM_UWORD *)&Code[loc * 4] = (offset & 0xFFFFFF) | (OP_JMP << 24); -#else - *(VM_UWORD *)&Code[loc * 4] = OP_JMP | (offset << 8); -#endif + assert(((offset << 8) >> 8) == offset); + Code[loc].op = OP_JMP; + Code[loc].i24 = offset; } //========================================================================== @@ -525,5 +517,5 @@ void VMFunctionBuilder::Backpatch(size_t loc, size_t target) void VMFunctionBuilder::BackpatchToHere(size_t loc) { - Backpatch(loc, Code.Size() / 4); + Backpatch(loc, Code.Size()); } diff --git a/src/zscript/vmbuilder.h b/src/zscript/vmbuilder.h index 328377f67..2399411f6 100644 --- a/src/zscript/vmbuilder.h +++ b/src/zscript/vmbuilder.h @@ -70,7 +70,7 @@ private: int MaxParam; int ActiveParam; - TArray<VM_UBYTE> Code; + TArray<VMOP> Code; // PARAM increases ActiveParam; CALL decreases it. void ParamChange(int delta); diff --git a/src/zscript/vmdisasm.cpp b/src/zscript/vmdisasm.cpp index 0864e881b..e8217815d 100644 --- a/src/zscript/vmdisasm.cpp +++ b/src/zscript/vmdisasm.cpp @@ -94,14 +94,6 @@ const VMOpInfo OpInfo[NUM_OPS] = #include "vmops.h" }; -#ifdef WORDS_BIGENDIAN -#define ABCs(x) ((*(VM_SWORD *)(x) << 8) >> 8) -#define JMPOFS(x) ((*(VM_SWORD *)(x) << 8) >> 6) -#else -#define ABCs(x) (*(VM_SWORD *)(x) >> 8) -#define JMPOFS(x) ((*(VM_SWORD *)(x) >> 6) & ~3) -#endif - static int print_reg(FILE *out, int col, int arg, int mode, int immshift, const VMScriptFunction *func); static int printf_wrapper(FILE *f, const char *fmt, ...) @@ -179,21 +171,21 @@ void VMDumpConstants(FILE *out, const VMScriptFunction *func) } } -void VMDisasm(FILE *out, const VM_UBYTE *code, int codesize, const VMScriptFunction *func) +void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction *func) { const char *name; int col; int mode; int a; - for (int i = 0; i < codesize; i += 4) + for (int i = 0; i < codesize; ++i) { - name = OpInfo[code[i]].Name; - mode = OpInfo[code[i]].Mode; - a = code[i+1]; + name = OpInfo[code[i].op].Name; + mode = OpInfo[code[i].op].Mode; + a = code[i].a; // String comparison encodes everything in a single instruction. - if (code[i] == OP_CMPS) + if (code[i].op == OP_CMPS) { switch (a & CMP_METHOD_MASK) { @@ -207,31 +199,31 @@ void VMDisasm(FILE *out, const VM_UBYTE *code, int codesize, const VMScriptFunct a &= CMP_CHECK | CMP_APPROX; } - printf_wrapper(out, "%08x: %02x%02x%02x%02x %-8s", i, code[i], code[i+1], code[i+2], code[i+3], name); + printf_wrapper(out, "%08x: %02x%02x%02x%02x %-8s", i << 2, code[i].op, code[i].a, code[i].b, code[i].c, name); col = 0; - switch (code[i]) + switch (code[i].op) { case OP_JMP: case OP_TRY: - col = printf_wrapper(out, "%08x", i + 4 + JMPOFS(&code[i])); + col = printf_wrapper(out, "%08x", i + 4 + (code[i].i24 << 2)); break; case OP_PARAMI: - col = printf_wrapper(out, "%d", ABCs(&code[i])); + col = printf_wrapper(out, "%d", code[i].i24); break; case OP_RET: - if (code[i+2] != REGT_NIL) + if (code[i].b != REGT_NIL) { - if ((code[i+2] & REGT_FINAL) && a == 0) + if ((code[i].b & REGT_FINAL) && a == 0) { - col = print_reg(out, 0, *(VM_UHALF *)&code[i+2], MODE_PARAM, 16, func); + col = print_reg(out, 0, code[i].i16u, MODE_PARAM, 16, func); } else { col = print_reg(out, 0, a, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func); - col += print_reg(out, col, *(VM_UHALF *)&code[i+2], MODE_PARAM, 16, func); - if (code[i+2] & REGT_FINAL) + col += print_reg(out, col, code[i].i16u, MODE_PARAM, 16, func); + if (code[i].b & REGT_FINAL) { col += printf_wrapper(out, " [final]"); } @@ -242,7 +234,7 @@ void VMDisasm(FILE *out, const VM_UBYTE *code, int codesize, const VMScriptFunct default: if ((mode & MODE_BCTYPE) == MODE_BCCAST) { - switch (code[i+3]) + switch (code[i].c) { case CAST_I2F: mode = MODE_AF | MODE_BI | MODE_CUNUSED; @@ -273,11 +265,11 @@ void VMDisasm(FILE *out, const VM_UBYTE *code, int codesize, const VMScriptFunct col = print_reg(out, 0, a, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func); if ((mode & MODE_BCTYPE) == MODE_BCTHROW) { - mode = (code[i+1] == 0) ? (MODE_BP | MODE_CUNUSED) : (MODE_BKP | MODE_CUNUSED); + mode = (code[i].a == 0) ? (MODE_BP | MODE_CUNUSED) : (MODE_BKP | MODE_CUNUSED); } else if ((mode & MODE_BCTYPE) == MODE_BCCATCH) { - switch (code[i+1]) + switch (code[i].a) { case 0: mode = MODE_BUNUSED | MODE_CUNUSED; @@ -298,12 +290,12 @@ void VMDisasm(FILE *out, const VM_UBYTE *code, int codesize, const VMScriptFunct } if ((mode & (MODE_BTYPE | MODE_CTYPE)) == MODE_BCJOINT) { - col += print_reg(out, col, *(VM_UHALF *)&code[i+2], (mode & MODE_BCTYPE) >> MODE_BCSHIFT, 16, func); + col += print_reg(out, col, code[i].i16u, (mode & MODE_BCTYPE) >> MODE_BCSHIFT, 16, func); } else { - col += print_reg(out, col, code[i+2], (mode & MODE_BTYPE) >> MODE_BSHIFT, 24, func); - col += print_reg(out, col, code[i+3], (mode & MODE_CTYPE) >> MODE_CSHIFT, 24, func); + col += print_reg(out, col, code[i].b, (mode & MODE_BTYPE) >> MODE_BSHIFT, 24, func); + col += print_reg(out, col, code[i].c, (mode & MODE_CTYPE) >> MODE_CSHIFT, 24, func); } break; } @@ -312,13 +304,13 @@ void VMDisasm(FILE *out, const VM_UBYTE *code, int codesize, const VMScriptFunct col = 30; } printf_wrapper(out, "%*c", 30 - col, ';'); - if (code[i] == OP_JMP || code[i] == OP_TRY) + if (code[i].op == OP_JMP || code[i].op == OP_TRY || code[i].op == OP_PARAMI) { - printf_wrapper(out, "%d\n", JMPOFS(&code[i]) >> 2); + printf_wrapper(out, "%d\n", code[i].i24); } else { - printf_wrapper(out, "%d,%d,%d\n", code[i+1], code[i+2], code[i+3]); + printf_wrapper(out, "%d,%d,%d\n", code[i].a, code[i].b, code[i].c); } } } @@ -385,40 +377,46 @@ static int print_reg(FILE *out, int col, int arg, int mode, int immshift, const case MODE_PARAM: { - union { VM_UHALF Together; struct { VM_UBYTE RegType, RegNum; }; } p; - p.Together = arg; - switch (p.RegType & (REGT_TYPE | REGT_KONST | REGT_MULTIREG)) + int regtype, regnum; +#ifdef __BIG_ENDIAN__ + regtype = (arg >> 8) & 255; + regnum = arg & 255; +#else + regtype = arg & 255; + regnum = (arg >> 8) & 255; +#endif + switch (regtype & (REGT_TYPE | REGT_KONST | REGT_MULTIREG)) { case REGT_INT: - return col+printf_wrapper(out, "d%d", p.RegNum); + return col+printf_wrapper(out, "d%d", regnum); case REGT_FLOAT: - return col+printf_wrapper(out, "f%d", p.RegNum); + return col+printf_wrapper(out, "f%d", regnum); case REGT_STRING: - return col+printf_wrapper(out, "s%d", p.RegNum); + return col+printf_wrapper(out, "s%d", regnum); case REGT_POINTER: - return col+printf_wrapper(out, "a%d", p.RegNum); + return col+printf_wrapper(out, "a%d", regnum); case REGT_FLOAT | REGT_MULTIREG: - return col+printf_wrapper(out, "v%d", p.RegNum); + return col+printf_wrapper(out, "v%d", regnum); case REGT_INT | REGT_KONST: - return col+print_reg(out, 0, p.RegNum, MODE_KI, 0, func); + return col+print_reg(out, 0, regnum, MODE_KI, 0, func); case REGT_FLOAT | REGT_KONST: - return col+print_reg(out, 0, p.RegNum, MODE_KF, 0, func); + return col+print_reg(out, 0, regnum, MODE_KF, 0, func); case REGT_STRING | REGT_KONST: - return col+print_reg(out, 0, p.RegNum, MODE_KS, 0, func); + return col+print_reg(out, 0, regnum, MODE_KS, 0, func); case REGT_POINTER | REGT_KONST: - return col+print_reg(out, 0, p.RegNum, MODE_KP, 0, func); + return col+print_reg(out, 0, regnum, MODE_KP, 0, func); case REGT_FLOAT | REGT_MULTIREG | REGT_KONST: - return col+print_reg(out, 0, p.RegNum, MODE_KV, 0, func); + return col+print_reg(out, 0, regnum, MODE_KV, 0, func); default: - if (p.RegType == REGT_NIL) + if (regtype == REGT_NIL) { return col+printf_wrapper(out, "nil"); } return col+printf_wrapper(out, "param[t=%d,%c,%c,n=%d]", - p.RegType & REGT_TYPE, - p.RegType & REGT_KONST ? 'k' : 'r', - p.RegType & REGT_MULTIREG ? 'm' : 's', - p.RegNum); + regtype & REGT_TYPE, + regtype & REGT_KONST ? 'k' : 'r', + regtype & REGT_MULTIREG ? 'm' : 's', + regnum); } } diff --git a/src/zscript/vmexec.cpp b/src/zscript/vmexec.cpp index 6ef11c29b..c05ebca92 100644 --- a/src/zscript/vmexec.cpp +++ b/src/zscript/vmexec.cpp @@ -9,7 +9,7 @@ #if COMPGOTO #define OP(x) x -#define NEXTOP do { unsigned op = *pc; a = pc[1]; pc += 4; goto *ops[op]; } while(0) +#define NEXTOP do { unsigned op = pc->op; a = pc->a; pc++; goto *ops[op]; } while(0) #else #define OP(x) case OP_##x #define NEXTOP break @@ -17,20 +17,14 @@ #define luai_nummod(a,b) ((a) - floor((a)/(b))*(b)) -#define A (*(pc - 3)) -#define B (*(pc - 2)) -#define C ( *(pc - 1)) -#define Cs (*(VM_SBYTE *)(pc - 1)) -#define BC (*(VM_UHALF *)(pc - 2)) -#define BCs (*(VM_SHALF *)(pc - 2)) - -#ifdef WORDS_BIGENDIAN -#define ABCs ((*(VM_SWORD *)(pc - 4) << 8) >> 8) -#define JMPOFS(x) ((*(VM_SWORD *)(x) << 8) >> 6) -#else -#define ABCs (*(VM_SWORD *)(pc - 4) >> 8) -#define JMPOFS(x) ((*(VM_SWORD *)(x) >> 6) & ~3) -#endif +#define A (pc[-1].a) +#define B (pc[-1].b) +#define C (pc[-1].c) +#define Cs (pc[-1].cs) +#define BC (pc[-1].i16u) +#define BCs (pc[-1].i16) +#define ABCs (pc[-1].i24) +#define JMPOFS(x) ((x)->i24) #define KC (konstd[C]) #define RC (reg.d[C]) @@ -52,10 +46,10 @@ #define CMPJMP(test) \ if ((test) == (a & CMP_CHECK)) { \ - assert(*pc == OP_JMP); \ - pc += 4 + JMPOFS(pc); \ + assert(pc->op == OP_JMP); \ + pc += 1 + JMPOFS(pc); \ } else { \ - pc += 4; \ + pc += 1; \ } enum @@ -112,7 +106,7 @@ struct VMExec_Unchecked #undef assert #include <assert.h> -int (*VMExec)(VMFrameStack *stack, const VM_UBYTE *pc, VMReturn *ret, int numret) = +int (*VMExec)(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret) = #ifdef NDEBUG VMExec_Unchecked::Exec #else diff --git a/src/zscript/vmexec.h b/src/zscript/vmexec.h index f8da2f291..07809909b 100644 --- a/src/zscript/vmexec.h +++ b/src/zscript/vmexec.h @@ -3,7 +3,7 @@ #endif -static int Exec(VMFrameStack *stack, const VM_UBYTE *pc, VMReturn *ret, int numret) +static int Exec(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret) { #if COMPGOTO static const void * const ops[256] = @@ -12,7 +12,7 @@ static int Exec(VMFrameStack *stack, const VM_UBYTE *pc, VMReturn *ret, int numr #include "vmops.h" }; #endif - const VM_UBYTE *exception_frames[MAX_TRY_DEPTH]; + const VMOP *exception_frames[MAX_TRY_DEPTH]; int try_depth = 0; VMFrame *f = stack->TopFrame(); VMScriptFunction *sfunc; @@ -52,7 +52,7 @@ begin: { #if !COMPGOTO VM_UBYTE op; - for(;;) switch(op = pc[0], a = pc[1], pc += 4, op) + for(;;) switch(op = pc->op, a = pc->a, pc++, op) #else NEXTOP; #endif @@ -383,17 +383,17 @@ begin: ASSERTD(a); if (reg.d[a] != BC) { - pc += 4; + pc++; } NEXTOP; OP(JMP): - pc += JMPOFS(pc - 4); + pc += JMPOFS(pc - 1); NEXTOP; OP(IJMP): ASSERTD(a); - pc += (BCs + reg.d[a]) << 2; - assert(*pc == OP_JMP); - pc += (1 + *((VM_SHALF *)pc + 1)) << 2; + pc += (BCs + reg.d[a]); + assert(pc->op == OP_JMP); + pc += 1 + JMPOFS(pc); NEXTOP; OP(PARAMI): assert(f->NumParam < sfunc->MaxParam); @@ -536,7 +536,7 @@ begin: { reg.param[--f->NumParam].~VMValue(); } - pc += C * 4; // Skip RESULTs + pc += C; // Skip RESULTs } NEXTOP; OP(RET): @@ -567,8 +567,8 @@ begin: { THROW(X_TOO_MANY_TRIES); } - assert(*(pc + JMPOFS(pc - 4)) == OP_CATCH); - exception_frames[try_depth++] = pc + JMPOFS(pc - 4); + assert((pc + JMPOFS(pc - 1))->op == OP_CATCH); + exception_frames[try_depth++] = pc + JMPOFS(pc - 1); NEXTOP; OP(UNTRY): assert(a <= try_depth); @@ -664,12 +664,12 @@ begin: } if (cmp == (a & CMP_CHECK)) { - assert(*pc == OP_JMP); - pc += 4 + JMPOFS(pc); + assert(pc->op == OP_JMP); + pc += 1 + JMPOFS(pc); } else { - pc += 4; + pc += 1; } } NEXTOP; @@ -1255,48 +1255,48 @@ begin: while(--try_depth >= 0) { pc = exception_frames[try_depth]; - assert(pc[0] == OP_CATCH); - while (pc[1] > 1) + assert(pc->op == OP_CATCH); + while (pc->a > 1) { // CATCH must be followed by JMP if it doesn't terminate a catch chain. - assert(pc[4] == OP_JMP); + assert(pc[1].op == OP_JMP); PClass *type; - int b = pc[2]; + int b = pc->b; - if (pc[1] == 2) + if (pc->a == 2) { ASSERTA(b); type = (PClass *)reg.a[b]; } else { - assert(pc[1] == 3); + assert(pc->a == 3); ASSERTKA(b); assert(konstatag[b] == ATAG_OBJECT); type = (PClass *)konsta[b].o; } - ASSERTA(pc[3]); + ASSERTA(pc->c); if (type == extype) { // Found a handler. Store the exception in pC, skip the JMP, // and begin executing its code. - reg.a[pc[3]] = exception; - reg.atag[pc[3]] = ATAG_OBJECT; - pc += 8; + reg.a[pc->c] = exception; + reg.atag[pc->c] = ATAG_OBJECT; + pc += 2; goto begin; } // This catch didn't handle it. Try the next one. - pc += 4 + JMPOFS(pc + 4); - assert(pc[0] == OP_CATCH); + pc += 1 + JMPOFS(pc + 1); + assert(pc->op == OP_CATCH); } - if (pc[1] == 1) + if (pc->a == 1) { // Catch any type of VMException. This terminates the chain. - ASSERTA(pc[3]); - reg.a[pc[3]] = exception; - reg.atag[pc[3]] = ATAG_OBJECT; - pc += 4; + ASSERTA(pc->c); + reg.a[pc->c] = exception; + reg.atag[pc->c] = ATAG_OBJECT; + pc += 1; goto begin; } // This frame failed. Try the next one out. @@ -1382,18 +1382,18 @@ static void DoCast(const VMRegisters ®, const VMFrame *f, int a, int b, int c // //=========================================================================== -static void FillReturns(const VMRegisters ®, VMFrame *frame, VMReturn *returns, const VM_UBYTE *retval, int numret) +static void FillReturns(const VMRegisters ®, VMFrame *frame, VMReturn *returns, const VMOP *retval, int numret) { int i, type, num; VMReturn *ret; assert(REGT_INT == 0 && REGT_FLOAT == 1 && REGT_STRING == 2 && REGT_POINTER == 3); - for (i = 0, ret = returns; i < numret; ++i, ++ret, retval += 4) + for (i = 0, ret = returns; i < numret; ++i, ++ret, ++retval) { - assert(retval[0] == OP_RESULT); // opcode - ret->RegType = type = retval[2]; - ret->RegNum = num = retval[3]; + assert(retval->op == OP_RESULT); // opcode + ret->RegType = type = retval->b; + ret->RegNum = num = retval->c; assert(!(type & REGT_KONST)); type &= REGT_TYPE; if (type < REGT_STRING) diff --git a/src/zscript/vmframe.cpp b/src/zscript/vmframe.cpp index 80766762b..0dce412c2 100644 --- a/src/zscript/vmframe.cpp +++ b/src/zscript/vmframe.cpp @@ -15,7 +15,7 @@ VMScriptFunction::VMScriptFunction() KonstS = NULL; KonstA = NULL; ExtraSpace = 0; - NumCodeBytes = 0; + CodeSize = 0; NumRegD = 0; NumRegF = 0; NumRegS = 0; @@ -37,12 +37,11 @@ VMScriptFunction::~VMScriptFunction() if (KonstA != NULL) M_Free(KonstA); } -VM_UBYTE *VMScriptFunction::AllocCode(int numops) +VMOP *VMScriptFunction::AllocCode(int numops) { assert(Code == NULL && numops > 0); - numops *= VM_OPSIZE; - NumCodeBytes = numops; - return Code = (VM_UBYTE *)M_Malloc(numops); + CodeSize = numops; + return Code = (VMOP *)M_Malloc(numops * sizeof(VMOP)); } int *VMScriptFunction::AllocKonstD(int numkonst) From e209a2f20809ba6a2bfa617fa0edec59fc60f86d Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 17 Oct 2009 01:38:54 +0000 Subject: [PATCH 016/232] - Stop aliasing strings onto names for function parameters. SVN r1923 (scripting) --- src/thingdef/thingdef_exp.h | 63 ++++++++++++++++++++++++++++ src/thingdef/thingdef_expression.cpp | 11 +++++ src/thingdef/thingdef_parse.cpp | 13 +++++- src/thingdef/thingdef_type.h | 3 +- src/zscript/vmdisasm.cpp | 4 +- wadsrc/static/actors/actor.txt | 2 +- 6 files changed, 90 insertions(+), 6 deletions(-) diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 719c1c66f..bcf08f175 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -97,6 +97,57 @@ struct ExpVal void *pointer; }; + ExpVal() + { + Type = VAL_Int; + Int = 0; + } + + ~ExpVal() + { + if (Type == VAL_String) + { + ((FString *)&pointer)->~FString(); + } + } + + ExpVal(const FString &str) + { + Type = VAL_String; + ::new(&pointer) FString(str); + } + + ExpVal(const ExpVal &o) + { + Type = o.Type; + if (o.Type == VAL_String) + { + ::new(&pointer) FString(*(FString *)&o.pointer); + } + else + { + memcpy(&Float, &o.Float, 8); + } + } + + ExpVal &operator=(const ExpVal &o) + { + if (Type == VAL_String) + { + ((FString *)&pointer)->~FString(); + } + Type = o.Type; + if (o.Type == VAL_String) + { + ::new(&pointer) FString(*(FString *)&o.pointer); + } + else + { + memcpy(&Float, &o.Float, 8); + } + return *this; + } + int GetInt() const { return Type == VAL_Int? Int : Type == VAL_Float? int(Float) : 0; @@ -107,6 +158,11 @@ struct ExpVal return Type == VAL_Int? double(Int) : Type == VAL_Float? Float : 0; } + const FString GetString() const + { + return Type == VAL_String ? *(FString *)&pointer : Type == VAL_Name ? FString(FName(ENamedName(Int)).GetChars()) : ""; + } + bool GetBool() const { return (Type == VAL_Int || Type == VAL_Sound) ? !!Int : Type == VAL_Float? Float!=0. : false; @@ -286,6 +342,13 @@ public: isresolved = true; } + FxConstant(const char *str, const FScriptPosition &pos) : FxExpression(pos) + { + ValueType = VAL_String; + value = ExpVal(FString(str)); + isresolved = true; + } + FxConstant(ExpVal cv, const FScriptPosition &pos) : FxExpression(pos) { value = cv; diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index a4f076ae2..7b32a132f 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -37,6 +37,7 @@ ** */ +#include <malloc.h> #include "actor.h" #include "sc_man.h" #include "tarray.h" @@ -404,8 +405,13 @@ ExpEmit FxParameter::Emit(VMFunctionBuilder *build) { build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(val.pointer, ATAG_STATE)); } + else if (val.Type == VAL_String) + { + build->Emit(OP_PARAM, 0, REGT_STRING | REGT_KONST, build->GetConstantString(val.GetString())); + } else { + build->Emit(OP_PARAM, 0, REGT_NIL, 0); ScriptPosition.Message(MSG_ERROR, "Cannot emit needed constant"); } } @@ -498,6 +504,11 @@ ExpEmit FxConstant::Emit(VMFunctionBuilder *build) out.RegType = REGT_POINTER; out.RegNum = build->GetConstantAddress(value.pointer, ATAG_STATE); } + else if (value.Type == VAL_String) + { + out.RegType = REGT_STRING; + out.RegNum = build->GetConstantString(value.GetString()); + } else { ScriptPosition.Message(MSG_ERROR, "Cannot emit needed constant"); diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 02fb125d6..fa2b1beec 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -85,12 +85,21 @@ FxExpression *ParseParameter(FScanner &sc, PClass *cls, char type, bool constant x = new FxClassTypeCast(RUNTIME_CLASS(AActor), new FxConstant(FName(sc.String), sc)); break; + case 'N': + case 'n': // name case 'T': case 't': // String sc.SetEscape(true); sc.MustGetString(); sc.SetEscape(false); - x = new FxConstant(sc.String[0]? FName(sc.String) : NAME_None, sc); + if (type == 'n' || type == 'N') + { + x = new FxConstant(sc.String[0] ? FName(sc.String) : NAME_None, sc); + } + else + { + x = new FxConstant(strbin1(sc.String), sc); + } break; case 'C': @@ -855,7 +864,7 @@ static void ParseActionDef (FScanner &sc, PClass *cls) case TK_Sound: type = 's'; break; case TK_String: type = 't'; break; - case TK_Name: type = 't'; break; + case TK_Name: type = 'n'; break; case TK_State: type = 'l'; break; case TK_Color: type = 'c'; break; case TK_Class: diff --git a/src/thingdef/thingdef_type.h b/src/thingdef/thingdef_type.h index 721cab61f..a89c80749 100644 --- a/src/thingdef/thingdef_type.h +++ b/src/thingdef/thingdef_type.h @@ -17,7 +17,8 @@ enum ExpValType VAL_Pointer, // Dereferenced variable (only used for addressing arrays for now.) VAL_Sound, // Sound identifier. Internally it's an int. VAL_Name, // A Name - VAL_Color, // A color. + VAL_String, // A string + VAL_Color, // A color VAL_State, // A State pointer // only used for accessing external variables to ensure proper conversion diff --git a/src/zscript/vmdisasm.cpp b/src/zscript/vmdisasm.cpp index e8217815d..9175cc096 100644 --- a/src/zscript/vmdisasm.cpp +++ b/src/zscript/vmdisasm.cpp @@ -166,7 +166,7 @@ void VMDumpConstants(FILE *out, const VMScriptFunction *func) printf_wrapper(out, "\nConstant strings:\n"); for (i = 0; i < func->NumKonstS; ++i) { - printf_wrapper(out, "%3d. %s\n", func->KonstS[k].GetChars()); + printf_wrapper(out, "%3d. %s\n", i, func->KonstS[i].GetChars()); } } } @@ -353,7 +353,7 @@ static int print_reg(FILE *out, int col, int arg, int mode, int immshift, const case MODE_KS: if (func != NULL) { - return col+printf_wrapper(out, "\"%s\"", func->KonstS[arg].GetChars()); + return col+printf_wrapper(out, "\"%.27s\"", func->KonstS[arg].GetChars()); } return col+printf_wrapper(out, "ks%d", arg); case MODE_KP: diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index b644b3511..8f66780ff 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -186,7 +186,7 @@ ACTOR Actor native //: Thinker action native A_JumpIfHealthLower(int health, state label); action native A_JumpIfCloser(float distance, state label); action native A_JumpIfInventory(class<Inventory> itemtype, int itemamount, state label); - action native A_JumpIfArmorType(string Type, state label, int amount = 1); + action native A_JumpIfArmorType(name Type, state label, int amount = 1); action native A_GiveInventory(class<Inventory> itemtype, int amount = 0); action native A_TakeInventory(class<Inventory> itemtype, int amount = 0); action native A_SpawnItem(class<Actor> itemtype = "Unknown", float distance = 0, float zheight = 0, bool useammo = true, bool transfer_translation = false); From 7ea11cd1698ccb0af53107171108656c277db433 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 17 Oct 2009 02:09:29 +0000 Subject: [PATCH 017/232] - Allocate VM script code and constants in a single block for better locality of reference. SVN r1924 (scripting) --- src/info.cpp | 6 +-- src/thingdef/thingdef_exp.h | 4 +- src/zscript/vm.h | 6 +-- src/zscript/vmbuilder.cpp | 11 ++-- src/zscript/vmframe.cpp | 105 +++++++++++++++++++++++------------- 5 files changed, 81 insertions(+), 51 deletions(-) diff --git a/src/info.cpp b/src/info.cpp index 4d56875e3..0edcfea5e 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -94,9 +94,9 @@ void FState::SetAction(PSymbolActionFunction *func, bool setdefaultparams) // Create a function for this state. VMScriptFunction *vmfunc = new VMScriptFunction; - VMOP *code = vmfunc->AllocCode(sizeof(codetemplate)/sizeof(VMOP)); - memcpy(code, codetemplate, sizeof(codetemplate)); - FVoidObj *konsta = vmfunc->AllocKonstA(2); + vmfunc->Alloc(sizeof(codetemplate)/sizeof(VMOP), 0, 0, 0, 2); + memcpy(vmfunc->Code, codetemplate, sizeof(codetemplate)); + FVoidObj *konsta = vmfunc->KonstA; VM_ATAG *atag = vmfunc->KonstATags(); konsta[0].v = (void *)func->Function; konsta[1].o = callfunc; diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index bcf08f175..99245d760 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -342,10 +342,10 @@ public: isresolved = true; } - FxConstant(const char *str, const FScriptPosition &pos) : FxExpression(pos) + FxConstant(const FString &str, const FScriptPosition &pos) : FxExpression(pos) { ValueType = VAL_String; - value = ExpVal(FString(str)); + value = ExpVal(str); isresolved = true; } diff --git a/src/zscript/vm.h b/src/zscript/vm.h index 16987ed72..acb4a0688 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -719,11 +719,7 @@ public: VMScriptFunction(); ~VMScriptFunction(); size_t PropagateMark(); - VMOP *AllocCode(int numops); - int *AllocKonstD(int numkonst); - double *AllocKonstF(int numkonst); - FString *AllocKonstS(int numkonst); - FVoidObj *AllocKonstA(int numkonst); + void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta); VM_ATAG *KonstATags() { return (VM_UBYTE *)(KonstA + NumKonstA); } const VM_ATAG *KonstATags() const { return (VM_UBYTE *)(KonstA + NumKonstA); } diff --git a/src/zscript/vmbuilder.cpp b/src/zscript/vmbuilder.cpp index b681c3d66..60fe7817c 100644 --- a/src/zscript/vmbuilder.cpp +++ b/src/zscript/vmbuilder.cpp @@ -38,26 +38,27 @@ VMScriptFunction *VMFunctionBuilder::MakeFunction() { VMScriptFunction *func = new VMScriptFunction; + func->Alloc(Code.Size(), NumIntConstants, NumFloatConstants, NumStringConstants, NumAddressConstants); + // Copy code block. - memcpy(func->AllocCode(Code.Size()), &Code[0], Code.Size() * sizeof(VMOP)); + memcpy(func->Code, &Code[0], Code.Size() * sizeof(VMOP)); // Create constant tables. if (NumIntConstants > 0) { - FillIntConstants(func->AllocKonstD(NumIntConstants)); + FillIntConstants(func->KonstD); } if (NumFloatConstants > 0) { - FillFloatConstants(func->AllocKonstF(NumFloatConstants)); + FillFloatConstants(func->KonstF); } if (NumAddressConstants > 0) { - func->AllocKonstA(NumAddressConstants); FillAddressConstants(func->KonstA, func->KonstATags()); } if (NumStringConstants > 0) { - FillStringConstants(func->AllocKonstS(NumStringConstants)); + FillStringConstants(func->KonstS); } // Assign required register space. diff --git a/src/zscript/vmframe.cpp b/src/zscript/vmframe.cpp index 0dce412c2..fdf2d42cc 100644 --- a/src/zscript/vmframe.cpp +++ b/src/zscript/vmframe.cpp @@ -30,46 +30,79 @@ VMScriptFunction::VMScriptFunction() VMScriptFunction::~VMScriptFunction() { - if (Code != NULL) M_Free(Code); - if (KonstD != NULL) M_Free(KonstD); - if (KonstF != NULL) M_Free(KonstF); - if (KonstS != NULL) delete[] KonstS; - if (KonstA != NULL) M_Free(KonstA); + if (Code != NULL) + { + if (KonstS != NULL) + { + for (int i = 0; i < NumKonstS; ++i) + { + KonstS[i].~FString(); + } + } + M_Free(Code); + } } -VMOP *VMScriptFunction::AllocCode(int numops) +void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta) { - assert(Code == NULL && numops > 0); + assert(Code == NULL); + assert(numops > 0); + assert(numkonstd >= 0 && numkonstd <= 255); + assert(numkonstf >= 0 && numkonstf <= 255); + assert(numkonsts >= 0 && numkonsts <= 255); + assert(numkonsta >= 0 && numkonsta <= 255); + void *mem = M_Malloc(numops * sizeof(VMOP) + + numkonstd * sizeof(int) + + numkonstf * sizeof(double) + + numkonsts * sizeof(FString) + + numkonsta * (sizeof(FVoidObj) + 1)); + Code = (VMOP *)mem; + mem = (void *)((VMOP *)mem + numops); + + if (numkonstd > 0) + { + KonstD = (int *)mem; + mem = (void *)((int *)mem + numkonstd); + } + else + { + KonstD = NULL; + } + if (numkonstf > 0) + { + KonstF = (double *)mem; + mem = (void *)((double *)mem + numkonstf); + } + else + { + KonstF = NULL; + } + if (numkonsts > 0) + { + KonstS = (FString *)mem; + for (int i = 0; i < numkonsts; ++i) + { + ::new(&KonstS[i]) FString; + } + mem = (void *)((FString *)mem + numkonsts); + } + else + { + KonstS = NULL; + } + if (numkonsta > 0) + { + KonstA = (FVoidObj *)mem; + } + else + { + KonstA = NULL; + } CodeSize = numops; - return Code = (VMOP *)M_Malloc(numops * sizeof(VMOP)); -} - -int *VMScriptFunction::AllocKonstD(int numkonst) -{ - assert(KonstD == NULL && numkonst > 0); - NumKonstD = numkonst; - return KonstD = (int *)M_Malloc(numkonst * sizeof(int)); -} - -double *VMScriptFunction::AllocKonstF(int numkonst) -{ - assert(KonstF == NULL && numkonst > 0); - NumKonstF = numkonst; - return KonstF = (double *)M_Malloc(numkonst * sizeof(double)); -} - -FString *VMScriptFunction::AllocKonstS(int numkonst) -{ - assert(KonstS == NULL && numkonst > 0); - NumKonstS = numkonst; - return KonstS = new FString[numkonst]; -} - -FVoidObj *VMScriptFunction::AllocKonstA(int numkonst) -{ - assert(KonstA == NULL && numkonst > 0); - NumKonstA = numkonst; - return KonstA = (FVoidObj *)M_Malloc(numkonst * sizeof(FVoidObj) + numkonst); + NumKonstD = numkonstd; + NumKonstF = numkonstf; + NumKonstS = numkonsts; + NumKonstA = numkonsta; } size_t VMScriptFunction::PropagateMark() From 739e684549f503ef69934bc7768d8671d6bb9173 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 12 Feb 2010 06:04:57 +0000 Subject: [PATCH 018/232] - Converted all action functions be directly callable by the VM (though they are not yet usable). SVN r2154 (scripting) --- src/d_dehacked.cpp | 2 +- src/dobjgc.cpp | 14 +- src/dobjtype.cpp | 6 +- src/dobjtype.h | 21 +- src/g_doom/a_arachnotron.cpp | 11 +- src/g_doom/a_archvile.cpp | 40 +- src/g_doom/a_bossbrain.cpp | 31 +- src/g_doom/a_bruiser.cpp | 7 +- src/g_doom/a_cacodemon.cpp | 7 +- src/g_doom/a_cyberdemon.cpp | 10 +- src/g_doom/a_demon.cpp | 5 +- src/g_doom/a_doomimp.cpp | 7 +- src/g_doom/a_doommisc.cpp | 3 + src/g_doom/a_doomweaps.cpp | 131 +- src/g_doom/a_fatso.cpp | 45 +- src/g_doom/a_keen.cpp | 10 +- src/g_doom/a_lostsoul.cpp | 15 +- src/g_doom/a_painelemental.cpp | 46 +- src/g_doom/a_possessed.cpp | 25 +- src/g_doom/a_revenant.cpp | 24 +- src/g_doom/a_scriptedmarine.cpp | 97 +- src/g_doom/a_spidermaster.cpp | 10 +- src/g_heretic/a_chicken.cpp | 23 +- src/g_heretic/a_dsparil.cpp | 39 +- src/g_heretic/a_hereticartifacts.cpp | 3 + src/g_heretic/a_hereticimp.cpp | 9 + src/g_heretic/a_hereticmisc.cpp | 34 +- src/g_heretic/a_hereticweaps.cpp | 163 ++- src/g_heretic/a_ironlich.cpp | 20 +- src/g_heretic/a_knight.cpp | 12 +- src/g_heretic/a_wizard.cpp | 16 +- src/g_hexen/a_bats.cpp | 11 +- src/g_hexen/a_bishop.cpp | 39 +- src/g_hexen/a_centaur.cpp | 3 + src/g_hexen/a_clericflame.cpp | 16 +- src/g_hexen/a_clericholy.cpp | 31 +- src/g_hexen/a_clericmace.cpp | 6 +- src/g_hexen/a_clericstaff.cpp | 21 +- src/g_hexen/a_dragon.cpp | 29 +- src/g_hexen/a_fighteraxe.cpp | 31 +- src/g_hexen/a_fighterhammer.cpp | 17 +- src/g_hexen/a_fighterplayer.cpp | 6 +- src/g_hexen/a_fighterquietus.cpp | 24 +- src/g_hexen/a_firedemon.cpp | 21 +- src/g_hexen/a_flechette.cpp | 17 +- src/g_hexen/a_fog.cpp | 21 +- src/g_hexen/a_heresiarch.cpp | 45 +- src/g_hexen/a_hexenspecialdecs.cpp | 44 +- src/g_hexen/a_iceguy.cpp | 19 +- src/g_hexen/a_korax.cpp | 34 +- src/g_hexen/a_magecone.cpp | 15 +- src/g_hexen/a_magelightning.cpp | 30 +- src/g_hexen/a_magestaff.cpp | 21 +- src/g_hexen/a_magewand.cpp | 3 + src/g_hexen/a_pig.cpp | 8 +- src/g_hexen/a_serpent.cpp | 53 +- src/g_hexen/a_spike.cpp | 15 + src/g_hexen/a_summon.cpp | 5 +- src/g_hexen/a_teleportother.cpp | 11 + src/g_hexen/a_wraith.cpp | 23 +- src/g_raven/a_minotaur.cpp | 64 +- src/g_shared/a_action.cpp | 76 +- src/g_shared/a_bridge.cpp | 12 +- src/g_shared/a_pickups.cpp | 12 + src/g_shared/a_randomspawner.cpp | 3 +- src/g_shared/a_specialspot.cpp | 23 +- src/g_shared/a_weapons.cpp | 18 +- src/g_strife/a_acolyte.cpp | 18 +- src/g_strife/a_alienspectres.cpp | 21 +- src/g_strife/a_crusader.cpp | 17 +- src/g_strife/a_entityboss.cpp | 12 + src/g_strife/a_inquisitor.cpp | 29 +- src/g_strife/a_loremaster.cpp | 3 + src/g_strife/a_oracle.cpp | 3 + src/g_strife/a_programmer.cpp | 20 +- src/g_strife/a_reaver.cpp | 3 + src/g_strife/a_rebels.cpp | 10 +- src/g_strife/a_sentinel.cpp | 15 +- src/g_strife/a_spectral.cpp | 14 +- src/g_strife/a_stalker.cpp | 17 +- src/g_strife/a_strifeitems.cpp | 3 + src/g_strife/a_strifestuff.cpp | 51 +- src/g_strife/a_strifeweapons.cpp | 140 +- src/g_strife/a_templar.cpp | 5 +- src/g_strife/a_thingstoblowup.cpp | 30 +- src/info.cpp | 68 +- src/info.h | 20 +- src/p_enemy.cpp | 156 ++- src/p_enemy.h | 4 +- src/p_mobj.cpp | 4 +- src/p_pspr.cpp | 65 +- src/p_user.cpp | 21 +- src/s_sound.cpp | 22 +- src/s_sound.h | 10 +- src/sound/fmod_wrap.h | 2 +- src/thingdef/olddecorations.cpp | 18 +- src/thingdef/thingdef.cpp | 8 +- src/thingdef/thingdef.h | 34 +- src/thingdef/thingdef_codeptr.cpp | 1462 ++++++++++++--------- src/thingdef/thingdef_data.cpp | 5 +- src/thingdef/thingdef_parse.cpp | 2 +- src/thingdef/thingdef_states.cpp | 7 +- src/win32/i_main.cpp | 2 +- src/zscript/vm.h | 74 +- src/zscript/vmexec.cpp | 2 +- wadsrc/static/actors/actor.txt | 8 +- wadsrc/static/actors/shared/debris.txt | 2 +- wadsrc/static/actors/shared/inventory.txt | 2 +- 108 files changed, 2827 insertions(+), 1295 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index c2859ef78..4889b2f75 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -1603,7 +1603,7 @@ static void SetPointer(FState *state, PSymbol *sym, int frame = 0) else { FString symname = sym->SymbolName.GetChars(); - state->SetAction(static_cast<PSymbolActionFunction*>(sym)); + state->SetAction(static_cast<PSymbolActionFunction*>(sym)->Function); // Note: CompareNoCase() calls stricmp() and therefore returns 0 when they're the same. for (unsigned int i = 0; i < MBFCodePointers.Size(); i++) diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index 101729037..3bdca01bd 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -71,6 +71,7 @@ #include "r_interpolate.h" #include "doomstat.h" #include "m_argv.h" +#include "autosegs.h" // MACROS ------------------------------------------------------------------ @@ -328,6 +329,17 @@ static void MarkRoot() SectorMarker->SecNum = 0; } Mark(SectorMarker); + // Mark action functions + if (!FinalGC) + { + FAutoSegIterator probe(ARegHead, ARegTail); + + while (*++probe != NULL) + { + AFuncDesc *afunc = (AFuncDesc *)*probe; + Mark(*(afunc->VMPointer)); + } + } // Mark classes for (unsigned j = 0; j < PClass::m_Types.Size(); ++j) { @@ -362,7 +374,7 @@ static void MarkRoot() // // Atomic // -// If their were any propagations that needed to be done atomicly, they +// If there were any propagations that needed to be done atomicly, they // would go here. It also sets things up for the sweep state. // //========================================================================== diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 236646820..33faac64d 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -224,7 +224,7 @@ void PClass::InsertIntoHash () } // Find a type, passed the name as a name -const PClass *PClass::FindClass (FName zaname) +PClass *PClass::FindClass (FName zaname) { if (zaname == NAME_None) { @@ -518,7 +518,9 @@ size_t PClass::PropagateMark() IMPLEMENT_ABSTRACT_CLASS(PSymbol); IMPLEMENT_CLASS(PSymbolConst); IMPLEMENT_CLASS(PSymbolVariable); -IMPLEMENT_CLASS(PSymbolActionFunction); +IMPLEMENT_POINTY_CLASS(PSymbolActionFunction) + DECLARE_POINTER(Function) +END_POINTERS IMPLEMENT_POINTY_CLASS(PSymbolVMFunction) DECLARE_POINTER(Function) END_POINTERS diff --git a/src/dobjtype.h b/src/dobjtype.h index 5ad13eaf6..b6ff7bc43 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -6,6 +6,7 @@ #endif #include "thingdef/thingdef_type.h" +#include "vm.h" // Symbol information ------------------------------------------------------- @@ -81,23 +82,27 @@ public: // parameters passed. struct FState; struct StateCallData; -typedef void (*actionf_p)(AActor *self, AActor *stateowner, FState *state, int parameters, StateCallData *statecall); +class VMFrameStack; +struct VMValue; +struct VMReturn; +typedef int (*actionf_p)(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret);/*(VM_ARGS)*/ +class VMFunction; class PSymbolActionFunction : public PSymbol { DECLARE_CLASS(PSymbolActionFunction, PSymbol); + HAS_OBJECT_POINTERS; public: FString Arguments; - actionf_p Function; + VMFunction *Function; int defaultparameterindex; PSymbolActionFunction(FName name) : PSymbol(name, SYM_ActionFunction) {} PSymbolActionFunction() : PSymbol(NAME_None, SYM_ActionFunction) {} }; -// A symbol table ----------------------------------------------------------- +// A VM function ------------------------------------------------------------ -class VMFunction; class PSymbolVMFunction : public PSymbol { DECLARE_CLASS(PSymbolVMFunction, PSymbol); @@ -195,10 +200,10 @@ public: } // Find a type, given its name. - static const PClass *FindClass (const char *name) { return FindClass (FName (name, true)); } - static const PClass *FindClass (const FString &name) { return FindClass (FName (name, true)); } - static const PClass *FindClass (ENamedName name) { return FindClass (FName (name)); } - static const PClass *FindClass (FName name); + static PClass *FindClass (const char *name) { return FindClass (FName (name, true)); } + static PClass *FindClass (const FString &name) { return FindClass (FName (name, true)); } + static PClass *FindClass (ENamedName name) { return FindClass (FName (name)); } + static PClass *FindClass (FName name); const PClass *FindClassTentative (FName name); // not static! static TArray<PClass *> m_Types; diff --git a/src/g_doom/a_arachnotron.cpp b/src/g_doom/a_arachnotron.cpp index 19c3bb63a..65e258720 100644 --- a/src/g_doom/a_arachnotron.cpp +++ b/src/g_doom/a_arachnotron.cpp @@ -8,18 +8,23 @@ */ DEFINE_ACTION_FUNCTION(AActor, A_BspiAttack) -{ +{ + PARAM_ACTION_PROLOGUE; + if (!self->target) - return; + return 0; A_FaceTarget (self); // launch a missile P_SpawnMissile (self, self->target, PClass::FindClass("ArachnotronPlasma")); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_BabyMetal) { + PARAM_ACTION_PROLOGUE; S_Sound (self, CHAN_BODY, "baby/walk", 1, ATTN_IDLE); - A_Chase (self); + A_Chase (stack, self); + return 0; } diff --git a/src/g_doom/a_archvile.cpp b/src/g_doom/a_archvile.cpp index 53e0ea202..88fd5f565 100644 --- a/src/g_doom/a_archvile.cpp +++ b/src/g_doom/a_archvile.cpp @@ -21,7 +21,9 @@ void A_Fire(AActor *self, int height); // DEFINE_ACTION_FUNCTION(AActor, A_VileStart) { + PARAM_ACTION_PROLOGUE; S_Sound (self, CHAN_VOICE, "vile/start", 1, ATTN_NORM); + return 0; } @@ -31,22 +33,27 @@ DEFINE_ACTION_FUNCTION(AActor, A_VileStart) // DEFINE_ACTION_FUNCTION(AActor, A_StartFire) { + PARAM_ACTION_PROLOGUE; S_Sound (self, CHAN_BODY, "vile/firestrt", 1, ATTN_NORM); A_Fire (self, 0); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_FireCrackle) { + PARAM_ACTION_PROLOGUE; S_Sound (self, CHAN_BODY, "vile/firecrkl", 1, ATTN_NORM); A_Fire (self, 0); + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Fire) { - ACTION_PARAM_START(1); - ACTION_PARAM_FIXED(height,0); + PARAM_ACTION_PROLOGUE; + PARAM_FIXED_OPT(height) { height = 0; } A_Fire(self, height); + return 0; } void A_Fire(AActor *self, int height) @@ -77,12 +84,13 @@ void A_Fire(AActor *self, int height) // DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileTarget) { - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(fire,0); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT(fire, AActor) { fire = PClass::FindClass("ArchvileFire"); } + AActor *fog; if (!self->target) - return; + return 0; A_FaceTarget (self); @@ -93,6 +101,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileTarget) fog->target = self; fog->tracer = self->target; A_Fire(fog, 0); + return 0; } @@ -102,25 +111,25 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileTarget) // A_VileAttack // DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileAttack) -{ - ACTION_PARAM_START(6); - ACTION_PARAM_SOUND(snd,0); - ACTION_PARAM_INT(dmg,1); - ACTION_PARAM_INT(blastdmg,2); - ACTION_PARAM_INT(blastrad,3); - ACTION_PARAM_FIXED(thrust,4); - ACTION_PARAM_NAME(dmgtype,5); +{ + PARAM_ACTION_PROLOGUE; + PARAM_SOUND_OPT (snd) { snd = "vile/stop"; } + PARAM_INT_OPT (dmg) { dmg = 20; } + PARAM_INT_OPT (blastdmg) { blastdmg = 70; } + PARAM_INT_OPT (blastrad) { blastrad = 70; } + PARAM_FIXED_OPT (thrust) { thrust = FRACUNIT; } + PARAM_NAME_OPT (dmgtype) { dmgtype = NAME_Fire; } AActor *fire, *target; angle_t an; if (NULL == (target = self->target)) - return; + return 0; A_FaceTarget (self); if (!P_CheckSight (self, target, 0) ) - return; + return 0; S_Sound (self, CHAN_WEAPON, snd, 1, ATTN_NORM); P_TraceBleed (dmg, target); @@ -139,4 +148,5 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileAttack) P_RadiusAttack (fire, self, blastdmg, blastrad, dmgtype, false); } target->velz = Scale(thrust, 1000, target->Mass); + return 0; } diff --git a/src/g_doom/a_bossbrain.cpp b/src/g_doom/a_bossbrain.cpp index 7764f2ecd..49517bb8e 100644 --- a/src/g_doom/a_bossbrain.cpp +++ b/src/g_doom/a_bossbrain.cpp @@ -18,13 +18,17 @@ static FRandom pr_spawnfly ("SpawnFly"); DEFINE_ACTION_FUNCTION(AActor, A_BrainAwake) { + PARAM_ACTION_PROLOGUE; // killough 3/26/98: only generates sound now S_Sound (self, CHAN_VOICE, "brain/sight", 1, ATTN_NONE); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_BrainPain) { + PARAM_ACTION_PROLOGUE; S_Sound (self, CHAN_VOICE, "brain/pain", 1, ATTN_NONE); + return 0; } static void BrainishExplosion (fixed_t x, fixed_t y, fixed_t z) @@ -53,6 +57,7 @@ static void BrainishExplosion (fixed_t x, fixed_t y, fixed_t z) DEFINE_ACTION_FUNCTION(AActor, A_BrainScream) { + PARAM_ACTION_PROLOGUE; fixed_t x; for (x = self->x - 196*FRACUNIT; x < self->x + 320*FRACUNIT; x += 8*FRACUNIT) @@ -61,34 +66,40 @@ DEFINE_ACTION_FUNCTION(AActor, A_BrainScream) 128 + (pr_brainscream() << (FRACBITS + 1))); } S_Sound (self, CHAN_VOICE, "brain/death", 1, ATTN_NONE); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_BrainExplode) { + PARAM_ACTION_PROLOGUE; fixed_t x = self->x + pr_brainexplode.Random2()*2048; fixed_t z = 128 + pr_brainexplode()*2*FRACUNIT; BrainishExplosion (x, self->y, z); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_BrainDie) { + PARAM_ACTION_PROLOGUE; + // [RH] If noexit, then don't end the level. if ((deathmatch || alwaysapplydmflags) && (dmflags & DF_NO_EXIT)) - return; + return 0; G_ExitLevel (0, false); + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BrainSpit) { + PARAM_ACTION_PROLOGUE; + PARAM_CLASS(spawntype, AActor); + DSpotState *state = DSpotState::GetSpotState(); AActor *targ; AActor *spit; bool isdefault = false; - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(spawntype, 0); - // shoot a cube at current target targ = state->GetNextInList(PClass::FindClass("BossTarget"), G_SkillProperty(SKILLP_EasyBossBrain)); @@ -135,6 +146,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BrainSpit) S_Sound (self, CHAN_WEAPON, "brain/spit", 1, ATTN_NONE); } } + return 0; } static void SpawnFly(AActor *self, const PClass *spawntype, FSoundID sound) @@ -255,10 +267,10 @@ static void SpawnFly(AActor *self, const PClass *spawntype, FSoundID sound) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnFly) { - FSoundID sound; + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT (spawntype, AActor) { spawntype = NULL; } - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(spawntype, 0); + FSoundID sound; if (spawntype != NULL) { @@ -266,15 +278,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnFly) } else { - spawntype = PClass::FindClass ("SpawnFire"); + spawntype = PClass::FindClass("SpawnFire"); sound = "brain/spawn"; } SpawnFly(self, spawntype, sound); + return 0; } // travelling cube sound DEFINE_ACTION_FUNCTION(AActor, A_SpawnSound) { + PARAM_ACTION_PROLOGUE; S_Sound (self, CHAN_BODY, "brain/cube", 1, ATTN_IDLE); SpawnFly(self, PClass::FindClass("SpawnFire"), "brain/spawn"); + return 0; } diff --git a/src/g_doom/a_bruiser.cpp b/src/g_doom/a_bruiser.cpp index 24c6c48eb..c4adec04f 100644 --- a/src/g_doom/a_bruiser.cpp +++ b/src/g_doom/a_bruiser.cpp @@ -3,8 +3,10 @@ static FRandom pr_bruisattack ("BruisAttack"); DEFINE_ACTION_FUNCTION(AActor, A_BruisAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target) - return; + return 0; if (self->CheckMeleeRange ()) { @@ -12,9 +14,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_BruisAttack) S_Sound (self, CHAN_WEAPON, "baron/melee", 1, ATTN_NORM); P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (damage, self->target, self); - return; + return 0; } // launch a missile P_SpawnMissile (self, self->target, PClass::FindClass("BaronBall")); + return 0; } diff --git a/src/g_doom/a_cacodemon.cpp b/src/g_doom/a_cacodemon.cpp index 0eb923890..1fd9b3ce4 100644 --- a/src/g_doom/a_cacodemon.cpp +++ b/src/g_doom/a_cacodemon.cpp @@ -14,8 +14,10 @@ static FRandom pr_headattack ("HeadAttack"); DEFINE_ACTION_FUNCTION(AActor, A_HeadAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target) - return; + return 0; A_FaceTarget (self); if (self->CheckMeleeRange ()) @@ -24,9 +26,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_HeadAttack) S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (damage, self->target, self); - return; + return 0; } // launch a missile P_SpawnMissile (self, self->target, PClass::FindClass("CacodemonBall")); + return 0; } diff --git a/src/g_doom/a_cyberdemon.cpp b/src/g_doom/a_cyberdemon.cpp index f13728e48..a7d7409ea 100644 --- a/src/g_doom/a_cyberdemon.cpp +++ b/src/g_doom/a_cyberdemon.cpp @@ -9,15 +9,21 @@ DEFINE_ACTION_FUNCTION(AActor, A_CyberAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target) - return; + return 0; A_FaceTarget (self); P_SpawnMissile (self, self->target, PClass::FindClass("Rocket")); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_Hoof) { + PARAM_ACTION_PROLOGUE; + S_Sound (self, CHAN_BODY, "cyber/hoof", 1, ATTN_IDLE); - A_Chase (self); + A_Chase (stack, self); + return 0; } diff --git a/src/g_doom/a_demon.cpp b/src/g_doom/a_demon.cpp index c890c32b0..c8df07cca 100644 --- a/src/g_doom/a_demon.cpp +++ b/src/g_doom/a_demon.cpp @@ -13,8 +13,10 @@ static FRandom pr_sargattack ("SargAttack"); DEFINE_ACTION_FUNCTION(AActor, A_SargAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target) - return; + return 0; A_FaceTarget (self); if (self->CheckMeleeRange ()) @@ -23,4 +25,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_SargAttack) P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (damage, self->target, self); } + return 0; } diff --git a/src/g_doom/a_doomimp.cpp b/src/g_doom/a_doomimp.cpp index 401fa4577..025fb7d27 100644 --- a/src/g_doom/a_doomimp.cpp +++ b/src/g_doom/a_doomimp.cpp @@ -17,8 +17,10 @@ static FRandom pr_troopattack ("TroopAttack"); // DEFINE_ACTION_FUNCTION(AActor, A_TroopAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target) - return; + return 0; A_FaceTarget (self); if (self->CheckMeleeRange ()) @@ -27,9 +29,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_TroopAttack) S_Sound (self, CHAN_WEAPON, "imp/melee", 1, ATTN_NORM); P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (damage, self->target, self); - return; + return 0; } // launch a missile P_SpawnMissile (self, self->target, PClass::FindClass("DoomImpBall")); + return 0; } diff --git a/src/g_doom/a_doommisc.cpp b/src/g_doom/a_doommisc.cpp index 898068d66..883cd3a5c 100644 --- a/src/g_doom/a_doommisc.cpp +++ b/src/g_doom/a_doommisc.cpp @@ -37,6 +37,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_BarrelDestroy) { + PARAM_ACTION_PROLOGUE; + if ((dmflags2 & DF2_BARRELS_RESPAWN) && (deathmatch || alwaysapplydmflags)) { @@ -48,5 +50,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_BarrelDestroy) { self->Destroy (); } + return 0; } diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index fcd6ea3a0..024495ce6 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -28,6 +28,8 @@ static FRandom pr_oldbfg ("OldBFG"); // DEFINE_ACTION_FUNCTION(AActor, A_Punch) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int damage; int pitch; @@ -39,7 +41,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Punch) if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } } @@ -63,6 +65,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Punch) linetarget->x, linetarget->y); } + return 0; } // @@ -70,6 +73,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_Punch) // DEFINE_ACTION_FUNCTION(AActor, A_FirePistol) { + PARAM_ACTION_PROLOGUE; + bool accurate; if (self->player != NULL) @@ -78,7 +83,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePistol) if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; P_SetPsprite (self->player, ps_flash, weapon->FindState(NAME_Flash)); } @@ -94,6 +99,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePistol) S_Sound (self, CHAN_WEAPON, "weapons/pistol", 1, ATTN_NORM); P_GunShot (self, accurate, PClass::FindClass(NAME_BulletPuff), P_BulletSlope (self)); + return 0; } // @@ -101,32 +107,34 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePistol) // DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) { + PARAM_ACTION_PROLOGUE; + PARAM_SOUND_OPT (fullsound) { fullsound = "weapons/sawfull"; } + PARAM_SOUND_OPT (hitsound) { hitsound = "weapons/sawhit"; } + PARAM_INT_OPT (damage) { damage = 2; } + PARAM_CLASS_OPT (pufftype, AActor) { pufftype = NULL; } + angle_t angle; player_t *player; AActor *linetarget; - ACTION_PARAM_START(4); - ACTION_PARAM_SOUND(fullsound, 0); - ACTION_PARAM_SOUND(hitsound, 1); - ACTION_PARAM_INT(damage, 2); - ACTION_PARAM_CLASS(pufftype, 3); - if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } - if (pufftype == NULL) pufftype = PClass::FindClass(NAME_BulletPuff); - if (damage == 0) damage = 2; + if (pufftype == NULL) + pufftype = PClass::FindClass(NAME_BulletPuff); + if (damage == 0) + damage = 2; - damage *= (pr_saw()%10+1); + damage *= (pr_saw()%10 + 1); angle = self->angle; angle += pr_saw.Random2() << 18; @@ -138,7 +146,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) if (!linetarget) { S_Sound (self, CHAN_WEAPON, fullsound, 1, ATTN_NORM); - return; + return 0; } S_Sound (self, CHAN_WEAPON, hitsound, 1, ATTN_NORM); @@ -160,6 +168,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) self->angle += ANG90/20; } self->flags |= MF_JUSTATTACKED; + return 0; } // @@ -167,12 +176,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) // DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun) { + PARAM_ACTION_PROLOGUE; + int i; player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } S_Sound (self, CHAN_WEAPON, "weapons/shotgf", 1, ATTN_NORM); @@ -180,7 +191,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun) if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; P_SetPsprite (player, ps_flash, weapon->FindState(NAME_Flash)); } player->mo->PlayAttacking2 (); @@ -189,6 +200,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun) for (i=0 ; i<7 ; i++) P_GunShot (self, false, PClass::FindClass(NAME_BulletPuff), pitch); + return 0; } // @@ -196,6 +208,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun) // DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun2) { + PARAM_ACTION_PROLOGUE; + int i; angle_t angle; int damage; @@ -203,7 +217,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun2) if (NULL == (player = self->player)) { - return; + return 0; } S_Sound (self, CHAN_WEAPON, "weapons/sshotf", 1, ATTN_NORM); @@ -211,7 +225,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun2) if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; P_SetPsprite (player, ps_flash, weapon->FindState(NAME_Flash)); } player->mo->PlayAttacking2 (); @@ -237,22 +251,29 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun2) pitch + (pr_fireshotgun2.Random2() * 332063), damage, NAME_None, NAME_BulletPuff); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_OpenShotgun2) { + PARAM_ACTION_PROLOGUE; S_Sound (self, CHAN_WEAPON, "weapons/sshoto", 1, ATTN_NORM); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_LoadShotgun2) { + PARAM_ACTION_PROLOGUE; S_Sound (self, CHAN_WEAPON, "weapons/sshotl", 1, ATTN_NORM); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_CloseShotgun2) { + PARAM_ACTION_PROLOGUE; S_Sound (self, CHAN_WEAPON, "weapons/sshotc", 1, ATTN_NORM); CALL_ACTION(A_ReFire, self); + return 0; } @@ -305,18 +326,20 @@ void P_SetSafeFlash(AWeapon * weapon, player_t * player, FState * flashstate, in // DEFINE_ACTION_FUNCTION(AActor, A_FireCGun) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (self == NULL || NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; S_Sound (self, CHAN_WEAPON, "weapons/chngun", 1, ATTN_NORM); @@ -340,6 +363,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireCGun) player->mo->PlayAttacking2 (); P_GunShot (self, !player->refire, PClass::FindClass(NAME_BulletPuff), P_BulletSlope (self)); + return 0; } // @@ -347,19 +371,22 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireCGun) // DEFINE_ACTION_FUNCTION(AActor, A_FireMissile) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } P_SpawnPlayerMissile (self, PClass::FindClass("Rocket")); + return 0; } // @@ -367,20 +394,23 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMissile) // DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireSTGrenade) { + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT(grenade, AActor) { grenade = PClass::FindClass("Grenade"); } + player_t *player; - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(grenade, 0); - if (grenade == NULL) return; + + if (grenade == NULL) + return 0; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } // Temporarily raise the pitch to send the grenade slightly upwards @@ -388,6 +418,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireSTGrenade) self->pitch -= (1152 << FRACBITS); P_SpawnPlayerMissile(self, grenade); self->pitch = SavedPlayerPitch; + return 0; } // @@ -395,17 +426,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireSTGrenade) // DEFINE_ACTION_FUNCTION(AActor, A_FirePlasma) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; FState *flash = weapon->FindState(NAME_Flash); if (flash != NULL) @@ -415,6 +448,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePlasma) } P_SpawnPlayerMissile (self, PClass::FindClass("PlasmaBall")); + return 0; } // @@ -451,22 +485,29 @@ static void FireRailgun(AActor *self, int RailOffset) DEFINE_ACTION_FUNCTION(AActor, A_FireRailgun) { + PARAM_ACTION_PROLOGUE; FireRailgun(self, 0); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_FireRailgunRight) { + PARAM_ACTION_PROLOGUE; FireRailgun(self, 10); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_FireRailgunLeft) { + PARAM_ACTION_PROLOGUE; FireRailgun(self, -10); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_RailWait) { // Okay, this was stupid. Just use a NULL function instead of this. + return 0; } // @@ -475,21 +516,24 @@ DEFINE_ACTION_FUNCTION(AActor, A_RailWait) DEFINE_ACTION_FUNCTION(AActor, A_FireBFG) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } P_SpawnPlayerMissile (self, 0, 0, 0, PClass::FindClass("BFGBall"), self->angle, NULL, NULL, !!(dmflags2 & DF2_NO_FREEAIMBFG)); + return 0; } // @@ -498,6 +542,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireBFG) // DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray) { + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT (spraytype, AActor) { spraytype = NULL; } + PARAM_INT_OPT (numrays) { numrays = 40; } + PARAM_INT_OPT (damagecnt) { damagecnt = 15; } + int i; int j; int damage; @@ -505,10 +554,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray) AActor *thingToHit; AActor *linetarget; - ACTION_PARAM_START(3); - ACTION_PARAM_CLASS(spraytype, 0); - ACTION_PARAM_INT(numrays, 1); - ACTION_PARAM_INT(damagecnt, 2); if (spraytype == NULL) spraytype = PClass::FindClass("BFGExtra"); if (numrays <= 0) numrays = 40; @@ -516,7 +561,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray) // [RH] Don't crash if no target if (!self->target) - return; + return 0; // offset angles from its attack angle for (i = 0; i < numrays; i++) @@ -544,6 +589,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray) P_DamageMobj (thingToHit, self->target, self->target, damage, NAME_BFGSplash); P_TraceBleed (damage, thingToHit, self->target); } + return 0; } // @@ -551,7 +597,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray) // DEFINE_ACTION_FUNCTION(AActor, A_BFGsound) { + PARAM_ACTION_PROLOGUE; S_Sound (self, CHAN_WEAPON, "weapons/bfgf", 1, ATTN_NORM); + return 0; } // @@ -565,6 +613,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BFGsound) DEFINE_ACTION_FUNCTION(AActor, A_FireOldBFG) { + PARAM_ACTION_PROLOGUE; const PClass * plasma[] = {PClass::FindClass("PlasmaBall1"), PClass::FindClass("PlasmaBall2")}; AActor * mo = NULL; @@ -572,14 +621,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireOldBFG) if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } self->player->extralight = 2; @@ -597,5 +646,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireOldBFG) self->angle = SavedPlayerAngle; self->pitch = SavedPlayerPitch; } - if (doesautoaim) self->player->ReadyWeapon->WeaponFlags &= ~WIF_NOAUTOAIM; // Restore autoaim setting + if (doesautoaim) + { // Restore autoaim setting + self->player->ReadyWeapon->WeaponFlags &= ~WIF_NOAUTOAIM; + } + return 0; } diff --git a/src/g_doom/a_fatso.cpp b/src/g_doom/a_fatso.cpp index e9dfa98e3..741622b9a 100644 --- a/src/g_doom/a_fatso.cpp +++ b/src/g_doom/a_fatso.cpp @@ -19,20 +19,23 @@ DEFINE_ACTION_FUNCTION(AActor, A_FatRaise) { + PARAM_ACTION_PROLOGUE; + A_FaceTarget (self); S_Sound (self, CHAN_WEAPON, "fatso/raiseguns", 1, ATTN_NORM); + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FatAttack1) { + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT(spawntype, AActor) { spawntype = NULL; } + AActor *missile; angle_t an; if (!self->target) - return; - - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(spawntype, 0); + return 0; if (spawntype == NULL) spawntype = PClass::FindClass("FatShot"); @@ -49,18 +52,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FatAttack1) missile->velx = FixedMul (missile->Speed, finecosine[an]); missile->vely = FixedMul (missile->Speed, finesine[an]); } + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FatAttack2) { + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT(spawntype, AActor) { spawntype = NULL; } + AActor *missile; angle_t an; if (!self->target) - return; - - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(spawntype, 0); + return 0; if (spawntype == NULL) spawntype = PClass::FindClass("FatShot"); @@ -77,18 +81,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FatAttack2) missile->velx = FixedMul (missile->Speed, finecosine[an]); missile->vely = FixedMul (missile->Speed, finesine[an]); } + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FatAttack3) { + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT(spawntype, AActor) { spawntype = NULL; } + AActor *missile; angle_t an; if (!self->target) - return; - - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(spawntype, 0); + return 0; if (spawntype == NULL) spawntype = PClass::FindClass("FatShot"); @@ -111,6 +116,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FatAttack3) missile->velx = FixedMul (missile->Speed, finecosine[an]); missile->vely = FixedMul (missile->Speed, finesine[an]); } + return 0; } // @@ -122,14 +128,14 @@ AActor * P_OldSpawnMissile(AActor * source, AActor * dest, const PClass *type); DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Mushroom) { - int i, j; + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT (spawntype, AActor) { spawntype = NULL; } + PARAM_INT_OPT (n) { n = 0; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_FIXED_OPT (vrange) { vrange = 4*FRACUNIT; } + PARAM_FIXED_OPT (hrange) { hrange = FRACUNIT/2; } - ACTION_PARAM_START(5); - ACTION_PARAM_CLASS(spawntype, 0); - ACTION_PARAM_INT(n, 1); - ACTION_PARAM_INT(flags, 2); - ACTION_PARAM_FIXED(vrange, 3); - ACTION_PARAM_FIXED(hrange, 4); + int i, j; if (n == 0) n = self->Damage; // GetMissileDamage (0, 1); if (spawntype == NULL) spawntype = PClass::FindClass("FatShot"); @@ -169,4 +175,5 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Mushroom) } } target->Destroy(); + return 0; } diff --git a/src/g_doom/a_keen.cpp b/src/g_doom/a_keen.cpp index 42231a915..2cb7196d1 100644 --- a/src/g_doom/a_keen.cpp +++ b/src/g_doom/a_keen.cpp @@ -13,8 +13,12 @@ // DOOM II special, map 32. // Uses special tag 666 by default. // + DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KeenDie) { + PARAM_ACTION_PROLOGUE; + PARAM_INT(doortag); + CALL_ACTION(A_NoBlocking, self); // scan the remaining thinkers to see if all Keens are dead @@ -27,14 +31,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KeenDie) if (other != self && other->health > 0 && other->IsA (matchClass)) { // other Keen not dead - return; + return 0; } } - ACTION_PARAM_START(1); - ACTION_PARAM_INT(doortag, 0); - EV_DoDoor (DDoor::doorOpen, NULL, NULL, doortag, 2*FRACUNIT, 0, 0, 0); + return 0; } diff --git a/src/g_doom/a_lostsoul.cpp b/src/g_doom/a_lostsoul.cpp index c648afaba..5851b158b 100644 --- a/src/g_doom/a_lostsoul.cpp +++ b/src/g_doom/a_lostsoul.cpp @@ -48,24 +48,29 @@ void A_SkullAttack(AActor *self, fixed_t speed) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SkullAttack) { - ACTION_PARAM_START(1); - ACTION_PARAM_FIXED(n, 0); + PARAM_ACTION_PROLOGUE; + PARAM_FIXED_OPT(speed) { speed = SKULLSPEED; } - if (n <= 0) n = SKULLSPEED; - A_SkullAttack(self, n); + if (speed <= 0) + speed = SKULLSPEED; + A_SkullAttack(self, speed); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_BetaSkullAttack) { + PARAM_ACTION_PROLOGUE; + int damage; if (!self || !self->target || self->target->GetSpecies() == self->GetSpecies()) - return; + return 0; S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); A_FaceTarget(self); damage = (pr_oldsoul()%8+1)*self->Damage; P_DamageMobj(self->target, self, self, damage, NAME_None); + return 0; } diff --git a/src/g_doom/a_painelemental.cpp b/src/g_doom/a_painelemental.cpp index bf0d0501b..f0c77eaef 100644 --- a/src/g_doom/a_painelemental.cpp +++ b/src/g_doom/a_painelemental.cpp @@ -12,13 +12,22 @@ DECLARE_ACTION(A_SkullAttack) -static const PClass *GetSpawnType(DECLARE_PARAMINFO) +static const PClass *GetSpawnType(VMValue *param) { - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(spawntype, 0); + const PClass *spawntype; - if (spawntype == NULL) spawntype = PClass::FindClass("LostSoul"); - return spawntype; + if (param == NULL || param->Type == REGT_NIL) + { + spawntype = NULL; + } + else + { + assert(param->Type == REGT_POINTER); + assert(param->atag == ATAG_OBJECT || param->a == NULL); + spawntype = (const PClass *)param->a; + } + + return (spawntype != NULL) ? spawntype : PClass::FindClass("LostSoul"); } @@ -38,7 +47,7 @@ void A_PainShootSkull (AActor *self, angle_t angle, const PClass *spawntype) int prestep; if (spawntype == NULL) return; - if (self->DamageType==NAME_Massacre) return; + if (self->DamageType == NAME_Massacre) return; // [RH] check to make sure it's not too close to the ceiling if (self->z + self->height + 8*FRACUNIT > self->ceilingz) @@ -139,34 +148,43 @@ void A_PainShootSkull (AActor *self, angle_t angle, const PClass *spawntype) // DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PainAttack) { - if (!self->target) - return; + PARAM_ACTION_PROLOGUE; - const PClass *spawntype = GetSpawnType(PUSH_PARAMINFO); + if (!self->target) + return 0; + + const PClass *spawntype = GetSpawnType(numparam > NAP ? ¶m[NAP] : NULL); A_FaceTarget (self); A_PainShootSkull (self, self->angle, spawntype); + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DualPainAttack) { - if (!self->target) - return; + PARAM_ACTION_PROLOGUE; - const PClass *spawntype = GetSpawnType(PUSH_PARAMINFO); + if (!self->target) + return 0; + + const PClass *spawntype = GetSpawnType(numparam > NAP ? ¶m[NAP] : NULL); A_FaceTarget (self); A_PainShootSkull (self, self->angle + ANG45, spawntype); A_PainShootSkull (self, self->angle - ANG45, spawntype); + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PainDie) { - if (self->target != NULL && self->IsFriend (self->target)) + PARAM_ACTION_PROLOGUE; + + if (self->target != NULL && self->IsFriend(self->target)) { // And I thought you were my friend! self->flags &= ~MF_FRIENDLY; } - const PClass *spawntype = GetSpawnType(PUSH_PARAMINFO); + const PClass *spawntype = GetSpawnType(numparam > NAP ? ¶m[NAP] : NULL); CALL_ACTION(A_NoBlocking, self); A_PainShootSkull (self, self->angle + ANG90, spawntype); A_PainShootSkull (self, self->angle + ANG180, spawntype); A_PainShootSkull (self, self->angle + ANG270, spawntype); + return 0; } diff --git a/src/g_doom/a_possessed.cpp b/src/g_doom/a_possessed.cpp index e435bff14..af34dfe5f 100644 --- a/src/g_doom/a_possessed.cpp +++ b/src/g_doom/a_possessed.cpp @@ -20,12 +20,14 @@ static FRandom pr_cposrefire ("CPosRefire"); // DEFINE_ACTION_FUNCTION(AActor, A_PosAttack) { + PARAM_ACTION_PROLOGUE; + int angle; int damage; int slope; if (!self->target) - return; + return 0; A_FaceTarget (self); angle = self->angle; @@ -35,6 +37,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PosAttack) angle += pr_posattack.Random2() << 20; damage = ((pr_posattack()%5)+1)*3; P_LineAttack (self, angle, MISSILERANGE, slope, damage, NAME_None, NAME_BulletPuff); + return 0; } static void A_SPosAttack2 (AActor *self) @@ -57,33 +60,41 @@ static void A_SPosAttack2 (AActor *self) DEFINE_ACTION_FUNCTION(AActor, A_SPosAttackUseAtkSound) { + PARAM_ACTION_PROLOGUE; + if (!self->target) - return; + return 0; S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); A_SPosAttack2 (self); + return 0; } // This version of the function, which uses a hard-coded sound, is // meant for Dehacked only. DEFINE_ACTION_FUNCTION(AActor, A_SPosAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target) - return; + return 0; S_Sound (self, CHAN_WEAPON, "shotguy/attack", 1, ATTN_NORM); A_SPosAttack2 (self); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_CPosAttack) { + PARAM_ACTION_PROLOGUE; + int angle; int bangle; int damage; int slope; if (!self->target) - return; + return 0; // [RH] Andy Baker's stealth monsters if (self->flags & MF_STEALTH) @@ -99,15 +110,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_CPosAttack) angle = bangle + (pr_cposattack.Random2() << 20); damage = ((pr_cposattack()%5)+1)*3; P_LineAttack (self, angle, MISSILERANGE, slope, damage, NAME_None, NAME_BulletPuff); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_CPosRefire) { + PARAM_ACTION_PROLOGUE; + // keep firing unless target got out of sight A_FaceTarget (self); if (pr_cposrefire() < 40) - return; + return 0; if (!self->target || P_HitFriend (self) @@ -116,4 +130,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_CPosRefire) { self->SetState (self->SeeState); } + return 0; } diff --git a/src/g_doom/a_revenant.cpp b/src/g_doom/a_revenant.cpp index 92a3dc13f..b03106892 100644 --- a/src/g_doom/a_revenant.cpp +++ b/src/g_doom/a_revenant.cpp @@ -19,11 +19,13 @@ static FRandom pr_skelfist ("SkelFist"); // A_SkelMissile // DEFINE_ACTION_FUNCTION(AActor, A_SkelMissile) -{ +{ + PARAM_ACTION_PROLOGUE; + AActor *missile; if (!self->target) - return; + return 0; A_FaceTarget (self); missile = P_SpawnMissileZ (self, self->z + 48*FRACUNIT, @@ -35,12 +37,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkelMissile) missile->y += missile->vely; missile->tracer = self->target; } + return 0; } #define TRACEANGLE (0xc000000) DEFINE_ACTION_FUNCTION(AActor, A_Tracer) { + PARAM_ACTION_PROLOGUE; + angle_t exact; fixed_t dist; fixed_t slope; @@ -57,7 +62,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer) // [RH] level.time is always 0-based, so nothing special to do here. if (level.time & 3) - return; + return 0; // spawn a puff of smoke behind the rocket P_SpawnPuff (self, PClass::FindClass(NAME_BulletPuff), self->x, self->y, self->z, 0, 3); @@ -74,7 +79,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer) dest = self->tracer; if (!dest || dest->health <= 0 || self->Speed == 0 || !self->CanSeek(dest)) - return; + return 0; // change angle exact = R_PointToAngle2 (self->x, self->y, dest->x, dest->y); @@ -124,21 +129,27 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer) else self->velz += FRACUNIT/8; } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_SkelWhoosh) { + PARAM_ACTION_PROLOGUE; + if (!self->target) - return; + return 0; A_FaceTarget (self); S_Sound (self, CHAN_WEAPON, "skeleton/swing", 1, ATTN_NORM); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_SkelFist) { + PARAM_ACTION_PROLOGUE; + if (!self->target) - return; + return 0; A_FaceTarget (self); @@ -149,4 +160,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkelFist) P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (damage, self->target, self); } + return 0; } diff --git a/src/g_doom/a_scriptedmarine.cpp b/src/g_doom/a_scriptedmarine.cpp index 9f6f54051..6ca1c1995 100644 --- a/src/g_doom/a_scriptedmarine.cpp +++ b/src/g_doom/a_scriptedmarine.cpp @@ -164,17 +164,19 @@ void AScriptedMarine::Tick () DEFINE_ACTION_FUNCTION(AActor, A_M_Refire) { + PARAM_ACTION_PROLOGUE; + if (self->target == NULL || self->target->health <= 0) { if (self->MissileState && pr_m_refire() < 160) { // Look for a new target most of the time if (P_LookForPlayers (self, true, NULL) && P_CheckMissileRange (self)) { // Found somebody new and in range, so don't stop shooting - return; + return 0; } } self->SetState (self->state + 1); - return; + return 0; } if ((self->MissileState == NULL && !self->CheckMeleeRange ()) || !P_CheckSight (self, self->target) || @@ -182,6 +184,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_Refire) { self->SetState (self->state + 1); } + return 0; } //============================================================================ @@ -192,15 +195,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_Refire) DEFINE_ACTION_FUNCTION(AActor, A_M_SawRefire) { + PARAM_ACTION_PROLOGUE; + if (self->target == NULL || self->target->health <= 0) { self->SetState (self->state + 1); - return; + return 0; } if (!self->CheckMeleeRange ()) { self->SetState (self->state + 1); } + return 0; } //============================================================================ @@ -211,10 +217,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_SawRefire) DEFINE_ACTION_FUNCTION(AActor, A_MarineNoise) { + PARAM_ACTION_PROLOGUE; + if (static_cast<AScriptedMarine *>(self)->CurrentWeapon == AScriptedMarine::WEAPON_Chainsaw) { S_Sound (self, CHAN_WEAPON, "weapons/sawidle", 1, ATTN_NORM); } + return 0; } //============================================================================ @@ -225,8 +234,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_MarineNoise) DEFINE_ACTION_FUNCTION(AActor, A_MarineChase) { + PARAM_ACTION_PROLOGUE; CALL_ACTION(A_MarineNoise, self); - A_Chase (self); + A_Chase (stack, self); + return 0; } //============================================================================ @@ -237,8 +248,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_MarineChase) DEFINE_ACTION_FUNCTION(AActor, A_MarineLook) { + PARAM_ACTION_PROLOGUE; CALL_ACTION(A_MarineNoise, self); CALL_ACTION(A_Look, self); + return 0; } //============================================================================ @@ -249,14 +262,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_MarineLook) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Saw) { - ACTION_PARAM_START(4); - ACTION_PARAM_SOUND(fullsound, 0); - ACTION_PARAM_SOUND(hitsound, 1); - ACTION_PARAM_INT(damage, 2); - ACTION_PARAM_CLASS(pufftype, 3); + PARAM_ACTION_PROLOGUE; + PARAM_SOUND_OPT (fullsound) { fullsound = "weapons/sawfull"; } + PARAM_SOUND_OPT (hitsound) { hitsound = "weapons/sawhit"; } + PARAM_INT_OPT (damage) { damage = 2; } + PARAM_CLASS_OPT (pufftype, AActor) { pufftype = NULL; } if (self->target == NULL) - return; + return 0; if (pufftype == NULL) pufftype = PClass::FindClass(NAME_BulletPuff); if (damage == 0) damage = 2; @@ -277,7 +290,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Saw) if (!linetarget) { S_Sound (self, CHAN_WEAPON, fullsound, 1, ATTN_NORM); - return; + return 0; } S_Sound (self, CHAN_WEAPON, hitsound, 1, ATTN_NORM); @@ -303,6 +316,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Saw) S_Sound (self, CHAN_WEAPON, fullsound, 1, ATTN_NORM); } //A_Chase (self); + return 0; } //============================================================================ @@ -338,10 +352,11 @@ static void MarinePunch(AActor *self, int damagemul) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Punch) { - ACTION_PARAM_START(1); - ACTION_PARAM_INT(mult, 0); + PARAM_ACTION_PROLOGUE; + PARAM_INT(mult); MarinePunch(self, mult); + return 0; } //============================================================================ @@ -374,16 +389,17 @@ void P_GunShot2 (AActor *mo, bool accurate, int pitch, const PClass *pufftype) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_FirePistol) { - if (self->target == NULL) - return; + PARAM_ACTION_PROLOGUE; + PARAM_BOOL(accurate); - ACTION_PARAM_START(1); - ACTION_PARAM_BOOL(accurate, 0); + if (self->target == NULL) + return 0; S_Sound (self, CHAN_WEAPON, "weapons/pistol", 1, ATTN_NORM); A_FaceTarget (self); P_GunShot2 (self, accurate, P_AimLineAttack (self, self->angle, MISSILERANGE), PClass::FindClass(NAME_BulletPuff)); + return 0; } //============================================================================ @@ -394,10 +410,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_FirePistol) DEFINE_ACTION_FUNCTION(AActor, A_M_FireShotgun) { + PARAM_ACTION_PROLOGUE; + int pitch; if (self->target == NULL) - return; + return 0; S_Sound (self, CHAN_WEAPON, "weapons/shotgf", 1, ATTN_NORM); A_FaceTarget (self); @@ -407,6 +425,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_FireShotgun) P_GunShot2 (self, false, pitch, PClass::FindClass(NAME_BulletPuff)); } self->special1 = level.maptime + 27; + return 0; } //============================================================================ @@ -417,6 +436,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_FireShotgun) DEFINE_ACTION_FUNCTION(AActor, A_M_CheckAttack) { + PARAM_ACTION_PROLOGUE; + if (self->special1 != 0 || self->target == NULL) { self->SetState (self->FindState("SkipAttack")); @@ -425,6 +446,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_CheckAttack) { A_FaceTarget (self); } + return 0; } //============================================================================ @@ -435,10 +457,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_CheckAttack) DEFINE_ACTION_FUNCTION(AActor, A_M_FireShotgun2) { + PARAM_ACTION_PROLOGUE; + int pitch; if (self->target == NULL) - return; + return 0; S_Sound (self, CHAN_WEAPON, "weapons/sshotf", 1, ATTN_NORM); A_FaceTarget (self); @@ -453,6 +477,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_FireShotgun2) NAME_None, PClass::FindClass(NAME_BulletPuff)); } self->special1 = level.maptime; + return 0; } //============================================================================ @@ -463,16 +488,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_FireShotgun2) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_FireCGun) { - if (self->target == NULL) - return; + PARAM_ACTION_PROLOGUE; + PARAM_BOOL(accurate); - ACTION_PARAM_START(1); - ACTION_PARAM_BOOL(accurate, 0); + if (self->target == NULL) + return 0; S_Sound (self, CHAN_WEAPON, "weapons/chngun", 1, ATTN_NORM); A_FaceTarget (self); P_GunShot2 (self, accurate, P_AimLineAttack (self, self->angle, MISSILERANGE), PClass::FindClass(NAME_BulletPuff)); + return 0; } //============================================================================ @@ -487,8 +513,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_FireCGun) DEFINE_ACTION_FUNCTION(AActor, A_M_FireMissile) { + PARAM_ACTION_PROLOGUE; + if (self->target == NULL) - return; + return 0; if (self->CheckMeleeRange ()) { // If too close, punch it @@ -499,6 +527,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_FireMissile) A_FaceTarget (self); P_SpawnMissile (self, self->target, PClass::FindClass("Rocket")); } + return 0; } //============================================================================ @@ -509,11 +538,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_FireMissile) DEFINE_ACTION_FUNCTION(AActor, A_M_FireRailgun) { + PARAM_ACTION_PROLOGUE; + if (self->target == NULL) - return; + return 0; CALL_ACTION(A_MonsterRail, self); self->special1 = level.maptime + 50; + return 0; } //============================================================================ @@ -524,12 +556,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_FireRailgun) DEFINE_ACTION_FUNCTION(AActor, A_M_FirePlasma) { + PARAM_ACTION_PROLOGUE; + if (self->target == NULL) - return; + return 0; A_FaceTarget (self); P_SpawnMissile (self, self->target, PClass::FindClass("PlasmaBall")); self->special1 = level.maptime + 20; + return 0; } //============================================================================ @@ -540,8 +575,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_FirePlasma) DEFINE_ACTION_FUNCTION(AActor, A_M_BFGsound) { + PARAM_ACTION_PROLOGUE; + if (self->target == NULL) - return; + return 0; if (self->special1 != 0) { @@ -554,6 +591,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_BFGsound) // Don't interrupt the firing sequence self->PainChance = 0; } + return 0; } //============================================================================ @@ -564,13 +602,16 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_BFGsound) DEFINE_ACTION_FUNCTION(AActor, A_M_FireBFG) { + PARAM_ACTION_PROLOGUE; + if (self->target == NULL) - return; + return 0; A_FaceTarget (self); P_SpawnMissile (self, self->target, PClass::FindClass("BFGBall")); self->special1 = level.maptime + 30; self->PainChance = MARINE_PAIN_CHANCE; + return 0; } //--------------------------------------------------------------------------- diff --git a/src/g_doom/a_spidermaster.cpp b/src/g_doom/a_spidermaster.cpp index a29561b56..f8d89ce5f 100644 --- a/src/g_doom/a_spidermaster.cpp +++ b/src/g_doom/a_spidermaster.cpp @@ -13,11 +13,13 @@ static FRandom pr_spidrefire ("SpidRefire"); DEFINE_ACTION_FUNCTION(AActor, A_SpidRefire) { + PARAM_ACTION_PROLOGUE; + // keep firing unless target got out of sight A_FaceTarget (self); if (pr_spidrefire() < 10) - return; + return 0; if (!self->target || P_HitFriend (self) @@ -26,10 +28,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpidRefire) { self->SetState (self->SeeState); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_Metal) { + PARAM_ACTION_PROLOGUE; + S_Sound (self, CHAN_BODY, "spider/walk", 1, ATTN_IDLE); - A_Chase (self); + A_Chase (stack, self); + return 0; } diff --git a/src/g_heretic/a_chicken.cpp b/src/g_heretic/a_chicken.cpp index 86e71774f..86c4243cb 100644 --- a/src/g_heretic/a_chicken.cpp +++ b/src/g_heretic/a_chicken.cpp @@ -66,9 +66,11 @@ void AChickenPlayer::MorphPlayerThink () DEFINE_ACTION_FUNCTION(AActor, A_ChicAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target) { - return; + return 0; } if (self->CheckMeleeRange()) { @@ -76,6 +78,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ChicAttack) P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (damage, self->target, self); } + return 0; } //---------------------------------------------------------------------------- @@ -86,6 +89,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_ChicAttack) DEFINE_ACTION_FUNCTION(AActor, A_Feathers) { + PARAM_ACTION_PROLOGUE; + int i; int count; AActor *mo; @@ -107,6 +112,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Feathers) mo->velz = FRACUNIT + (pr_feathers() << 9); mo->SetState (mo->SpawnState + (pr_feathers()&7)); } + return 0; } //--------------------------------------------------------------------------- @@ -132,14 +138,17 @@ void P_UpdateBeak (AActor *self) DEFINE_ACTION_FUNCTION(AActor, A_BeakRaise) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } player->psprites[ps_weapon].sy = WEAPONTOP; P_SetPsprite (player, ps_weapon, player->ReadyWeapon->GetReadyState()); + return 0; } //---------------------------------------------------------------------------- @@ -161,6 +170,8 @@ void P_PlayPeck (AActor *chicken) DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL1) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int damage; int slope; @@ -169,7 +180,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL1) if (NULL == (player = self->player)) { - return; + return 0; } damage = 1 + (pr_beakatkpl1()&3); @@ -184,6 +195,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL1) P_PlayPeck (player->mo); player->chickenPeck = 12; player->psprites[ps_weapon].tics -= pr_beakatkpl1() & 7; + return 0; } //---------------------------------------------------------------------------- @@ -194,6 +206,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL1) DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL2) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int damage; int slope; @@ -202,7 +216,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL2) if (NULL == (player = self->player)) { - return; + return 0; } damage = pr_beakatkpl2.HitDice (4); @@ -217,4 +231,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL2) P_PlayPeck (player->mo); player->chickenPeck = 12; player->psprites[ps_weapon].tics -= pr_beakatkpl2()&3; + return 0; } diff --git a/src/g_heretic/a_dsparil.cpp b/src/g_heretic/a_dsparil.cpp index b6a8c6a1e..8ec664d84 100644 --- a/src/g_heretic/a_dsparil.cpp +++ b/src/g_heretic/a_dsparil.cpp @@ -28,8 +28,11 @@ static FRandom pr_bluespark ("BlueSpark"); DEFINE_ACTION_FUNCTION(AActor, A_Sor1Pain) { + PARAM_ACTION_PROLOGUE; + self->special1 = 20; // Number of steps to walk fast CALL_ACTION(A_Pain, self); + return 0; } //---------------------------------------------------------------------------- @@ -40,12 +43,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_Sor1Pain) DEFINE_ACTION_FUNCTION(AActor, A_Sor1Chase) { + PARAM_ACTION_PROLOGUE; + if (self->special1) { self->special1--; self->tics -= 3; } - A_Chase(self); + A_Chase(stack, self); + return 0; } //---------------------------------------------------------------------------- @@ -58,13 +64,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_Sor1Chase) DEFINE_ACTION_FUNCTION(AActor, A_Srcr1Attack) { + PARAM_ACTION_PROLOGUE; + AActor *mo; fixed_t velz; angle_t angle; if (!self->target) { - return; + return 0; } S_Sound (self, CHAN_BODY, self->AttackSound, 1, ATTN_NORM); if (self->CheckMeleeRange ()) @@ -72,7 +80,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Srcr1Attack) int damage = pr_scrc1atk.HitDice (8); P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (damage, self->target, self); - return; + return 0; } const PClass *fx = PClass::FindClass("SorcererFX1"); @@ -103,6 +111,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Srcr1Attack) } } } + return 0; } //---------------------------------------------------------------------------- @@ -113,6 +122,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_Srcr1Attack) DEFINE_ACTION_FUNCTION(AActor, A_SorcererRise) { + PARAM_ACTION_PROLOGUE; + AActor *mo; self->flags &= ~MF_SOLID; @@ -120,6 +131,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcererRise) mo->SetState (mo->FindState("Rise")); mo->angle = self->angle; mo->CopyFriendliness (self, true); + return 0; } //---------------------------------------------------------------------------- @@ -165,6 +177,7 @@ void P_DSparilTeleport (AActor *actor) DEFINE_ACTION_FUNCTION(AActor, A_Srcr2Decide) { + PARAM_ACTION_PROLOGUE; static const int chance[] = { @@ -181,6 +194,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Srcr2Decide) { P_DSparilTeleport (self); } + return 0; } //---------------------------------------------------------------------------- @@ -191,11 +205,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_Srcr2Decide) DEFINE_ACTION_FUNCTION(AActor, A_Srcr2Attack) { + PARAM_ACTION_PROLOGUE; + int chance; if (!self->target) { - return; + return 0; } S_Sound (self, CHAN_BODY, self->AttackSound, 1, ATTN_NONE); if (self->CheckMeleeRange()) @@ -203,7 +219,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Srcr2Attack) int damage = pr_s2a.HitDice (20); P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (damage, self->target, self); - return; + return 0; } chance = self->health < self->SpawnHealth()/2 ? 96 : 48; if (pr_s2a() < chance) @@ -220,6 +236,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Srcr2Attack) { // Blue bolt P_SpawnMissile (self, self->target, PClass::FindClass("Sorcerer2FX1")); } + return 0; } //---------------------------------------------------------------------------- @@ -230,6 +247,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_Srcr2Attack) DEFINE_ACTION_FUNCTION(AActor, A_BlueSpark) { + PARAM_ACTION_PROLOGUE; + int i; AActor *mo; @@ -240,6 +259,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BlueSpark) mo->vely = pr_bluespark.Random2() << 9; mo->velz = FRACUNIT + (pr_bluespark()<<8); } + return 0; } //---------------------------------------------------------------------------- @@ -250,6 +270,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_BlueSpark) DEFINE_ACTION_FUNCTION(AActor, A_GenWizard) { + PARAM_ACTION_PROLOGUE; + AActor *mo; mo = Spawn("Wizard", self->x, self->y, self->z, ALLOW_REPLACE); @@ -273,6 +295,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_GenWizard) Spawn<ATeleportFog> (self->x, self->y, self->z, ALLOW_REPLACE); } } + return 0; } //---------------------------------------------------------------------------- @@ -283,8 +306,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_GenWizard) DEFINE_ACTION_FUNCTION(AActor, A_Sor2DthInit) { + PARAM_ACTION_PROLOGUE; + self->special1 = 7; // Animation loop counter P_Massacre (); // Kill monsters early + return 0; } //---------------------------------------------------------------------------- @@ -295,9 +321,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_Sor2DthInit) DEFINE_ACTION_FUNCTION(AActor, A_Sor2DthLoop) { + PARAM_ACTION_PROLOGUE; + if (--self->special1) { // Need to loop self->SetState (self->FindState("DeathLoop")); } + return 0; } diff --git a/src/g_heretic/a_hereticartifacts.cpp b/src/g_heretic/a_hereticartifacts.cpp index 1b7a79966..accb8afa9 100644 --- a/src/g_heretic/a_hereticartifacts.cpp +++ b/src/g_heretic/a_hereticartifacts.cpp @@ -47,6 +47,8 @@ bool AArtiTomeOfPower::Use (bool pickup) DEFINE_ACTION_FUNCTION(AActor, A_TimeBomb) { + PARAM_ACTION_PROLOGUE; + self->z += 32*FRACUNIT; self->RenderStyle = STYLE_Add; self->alpha = FRACUNIT; @@ -55,6 +57,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_TimeBomb) { P_HitFloor (self); } + return 0; } class AArtiTimeBomb : public AInventory diff --git a/src/g_heretic/a_hereticimp.cpp b/src/g_heretic/a_hereticimp.cpp index b2c92426e..6d25905a9 100644 --- a/src/g_heretic/a_hereticimp.cpp +++ b/src/g_heretic/a_hereticimp.cpp @@ -19,6 +19,8 @@ static FRandom pr_imp ("ImpExplode"); DEFINE_ACTION_FUNCTION(AActor, A_ImpExplode) { + PARAM_ACTION_PROLOGUE; + AActor *chunk; self->flags &= ~MF_NOGRAVITY; @@ -36,6 +38,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ImpExplode) { // Extreme death crash self->SetState (self->FindState("XCrash")); } + return 0; } //---------------------------------------------------------------------------- @@ -46,8 +49,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_ImpExplode) DEFINE_ACTION_FUNCTION(AActor, A_ImpDeath) { + PARAM_ACTION_PROLOGUE; + self->flags &= ~MF_SOLID; self->flags2 |= MF2_FLOORCLIP; + return 0; } //---------------------------------------------------------------------------- @@ -58,9 +64,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_ImpDeath) DEFINE_ACTION_FUNCTION(AActor, A_ImpXDeath1) { + PARAM_ACTION_PROLOGUE; + self->flags &= ~MF_SOLID; self->flags |= MF_NOGRAVITY; self->flags2 |= MF2_FLOORCLIP; self->special1 = 666; // Flag the crash routine + return 0; } diff --git a/src/g_heretic/a_hereticmisc.cpp b/src/g_heretic/a_hereticmisc.cpp index 7fc249378..141dff651 100644 --- a/src/g_heretic/a_hereticmisc.cpp +++ b/src/g_heretic/a_hereticmisc.cpp @@ -42,8 +42,8 @@ static FRandom pr_volcimpact ("VolcBallImpact"); DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PodPain) { - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(gootype, 0); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT (gootype, AActor) { gootype = PClass::FindClass("PodGoo"); } int count; int chance; @@ -52,7 +52,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PodPain) chance = pr_podpain (); if (chance < 128) { - return; + return 0; } for (count = chance > 240 ? 2 : 1; count; count--) { @@ -62,6 +62,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PodPain) goo->vely = pr_podpain.Random2() << 9; goo->velz = FRACUNIT/2 + (pr_podpain() << 9); } + return 0; } //---------------------------------------------------------------------------- @@ -72,15 +73,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PodPain) DEFINE_ACTION_FUNCTION(AActor, A_RemovePod) { + PARAM_ACTION_PROLOGUE; + AActor *mo; - if ( (mo = self->master)) + if ( (mo = self->master) ) { if (mo->special1 > 0) { mo->special1--; } } + return 0; } //---------------------------------------------------------------------------- @@ -93,8 +97,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_RemovePod) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MakePod) { - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(podtype, 0); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT(podtype, AActor) { podtype = PClass::FindClass("Pod"); } AActor *mo; fixed_t x; @@ -103,7 +107,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MakePod) if (self->special1 == MAX_GEN_PODS) { // Too many generated pods - return; + return 0; } x = self->x; y = self->y; @@ -112,14 +116,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MakePod) if (!P_CheckPosition (mo, x, y)) { // Didn't fit mo->Destroy (); - return; + return 0; } mo->SetState (mo->FindState("Grow")); P_ThrustMobj (mo, pr_makepod()<<24, (fixed_t)(4.5*FRACUNIT)); S_Sound (mo, CHAN_BODY, self->AttackSound, 1, ATTN_IDLE); self->special1++; // Increment generated pod count mo->master = self; // Link the generator to the pod - return; + return 0; } //---------------------------------------------------------------------------- @@ -130,10 +134,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MakePod) DEFINE_ACTION_FUNCTION(AActor, A_AccTeleGlitter) { + PARAM_ACTION_PROLOGUE; + if (++self->health > 35) { self->velz += self->velz/2; } + return 0; } @@ -145,7 +152,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_AccTeleGlitter) DEFINE_ACTION_FUNCTION(AActor, A_VolcanoSet) { + PARAM_ACTION_PROLOGUE; + self->tics = 105 + (pr_volcano() & 127); + return 0; } //---------------------------------------------------------------------------- @@ -156,6 +166,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_VolcanoSet) DEFINE_ACTION_FUNCTION(AActor, A_VolcanoBlast) { + PARAM_ACTION_PROLOGUE; + int i; int count; AActor *blast; @@ -176,6 +188,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_VolcanoBlast) S_Sound (blast, CHAN_BODY, "world/volcano/shoot", 1, ATTN_NORM); P_CheckMissileSpawn (blast); } + return 0; } //---------------------------------------------------------------------------- @@ -186,6 +199,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_VolcanoBlast) DEFINE_ACTION_FUNCTION(AActor, A_VolcBallImpact) { + PARAM_ACTION_PROLOGUE; + int i; AActor *tiny; angle_t angle; @@ -210,5 +225,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_VolcBallImpact) tiny->velz = FRACUNIT + (pr_volcimpact() << 9); P_CheckMissileSpawn (tiny); } + return 0; } diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index f17e72545..c6c22154d 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -61,6 +61,8 @@ extern bool P_AutoUseChaosDevice (player_t *player); DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StaffAttack) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int slope; player_t *player; @@ -68,18 +70,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StaffAttack) if (NULL == (player = self->player)) { - return; + return 0; } - ACTION_PARAM_START(2); - ACTION_PARAM_INT(damage, 0); - ACTION_PARAM_CLASS(puff, 1); + PARAM_INT (damage); + PARAM_CLASS (puff, AActor); AWeapon *weapon = player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } if (puff == NULL) puff = PClass::FindClass(NAME_BulletPuff); // just to be sure angle = self->angle; @@ -93,6 +94,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StaffAttack) self->angle = R_PointToAngle2 (self->x, self->y, linetarget->x, linetarget->y); } + return 0; } @@ -104,20 +106,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StaffAttack) DEFINE_ACTION_FUNCTION(AActor, A_FireGoldWandPL1) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int damage; player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } angle_t pitch = P_BulletSlope(self); damage = 7+(pr_fgw()&7); @@ -128,6 +132,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireGoldWandPL1) } P_LineAttack (self, angle, PLAYERMISSILERANGE, pitch, damage, NAME_None, "GoldWandPuff1"); S_Sound (self, CHAN_WEAPON, "weapons/wandhit", 1, ATTN_NORM); + return 0; } //---------------------------------------------------------------------------- @@ -138,6 +143,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireGoldWandPL1) DEFINE_ACTION_FUNCTION(AActor, A_FireGoldWandPL2) { + PARAM_ACTION_PROLOGUE; + int i; angle_t angle; int damage; @@ -146,14 +153,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireGoldWandPL2) if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } angle_t pitch = P_BulletSlope(self); velz = FixedMul (GetDefaultByName("GoldWandFX2")->Speed, @@ -168,6 +175,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireGoldWandPL2) angle += ((ANG45/8)*2)/4; } S_Sound (self, CHAN_WEAPON, "weapons/wandhit", 1, ATTN_NORM); + return 0; } //---------------------------------------------------------------------------- @@ -178,22 +186,25 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireGoldWandPL2) DEFINE_ACTION_FUNCTION(AActor, A_FireCrossbowPL1) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } P_SpawnPlayerMissile (self, PClass::FindClass("CrossbowFX1")); P_SpawnPlayerMissile (self, PClass::FindClass("CrossbowFX3"), self->angle-(ANG45/10)); P_SpawnPlayerMissile (self, PClass::FindClass("CrossbowFX3"), self->angle+(ANG45/10)); + return 0; } //---------------------------------------------------------------------------- @@ -204,24 +215,27 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireCrossbowPL1) DEFINE_ACTION_FUNCTION(AActor, A_FireCrossbowPL2) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } P_SpawnPlayerMissile (self, PClass::FindClass("CrossbowFX2")); P_SpawnPlayerMissile (self, PClass::FindClass("CrossbowFX2"), self->angle-(ANG45/10)); P_SpawnPlayerMissile (self, PClass::FindClass("CrossbowFX2"), self->angle+(ANG45/10)); P_SpawnPlayerMissile (self, PClass::FindClass("CrossbowFX3"), self->angle-(ANG45/5)); P_SpawnPlayerMissile (self, PClass::FindClass("CrossbowFX3"), self->angle+(ANG45/5)); + return 0; } //--------------------------------------------------------------------------- @@ -232,6 +246,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireCrossbowPL2) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int damage; int slope; @@ -243,17 +259,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack) if (NULL == (player = self->player)) { - return; + return 0; } - ACTION_PARAM_START(1); - ACTION_PARAM_INT(power, 0); + PARAM_INT(power); AWeapon *weapon = player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } player->psprites[ps_weapon].sx = ((pr_gatk()&3)-2) * FRACUNIT; player->psprites[ps_weapon].sy = WEAPONTOP + (pr_gatk()&3) * FRACUNIT; @@ -281,7 +296,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack) player->extralight = !player->extralight; } S_Sound (self, CHAN_AUTO, "weapons/gauntletson", 1, ATTN_NORM); - return; + return 0; } randVal = pr_gatk(); if (randVal < 64) @@ -323,6 +338,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack) self->angle += ANG90/20; } self->flags |= MF_JUSTATTACKED; + return 0; } // --- Mace ----------------------------------------------------------------- @@ -406,24 +422,26 @@ void FireMacePL1B (AActor *actor) DEFINE_ACTION_FUNCTION(AActor, A_FireMacePL1) { + PARAM_ACTION_PROLOGUE; + AActor *ball; player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } if (pr_maceatk() < 28) { FireMacePL1B (self); - return; + return 0; } AWeapon *weapon = player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } player->psprites[ps_weapon].sx = ((pr_maceatk()&3)-2)*FRACUNIT; player->psprites[ps_weapon].sy = WEAPONTOP+(pr_maceatk()&3)*FRACUNIT; @@ -433,6 +451,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMacePL1) { ball->special1 = 16; // tics till dropoff } + return 0; } //---------------------------------------------------------------------------- @@ -443,14 +462,16 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMacePL1) DEFINE_ACTION_FUNCTION(AActor, A_MacePL1Check) { + PARAM_ACTION_PROLOGUE; + if (self->special1 == 0) { - return; + return 0; } self->special1 -= 4; if (self->special1 > 0) { - return; + return 0; } self->special1 = 0; self->flags &= ~MF_NOGRAVITY; @@ -469,6 +490,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MacePL1Check) self->vely = (int)(self->vely * velscale); #endif self->velz -= self->velz >> 1; + return 0; } //---------------------------------------------------------------------------- @@ -479,6 +501,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_MacePL1Check) DEFINE_ACTION_FUNCTION(AActor, A_MaceBallImpact) { + PARAM_ACTION_PROLOGUE; + if ((self->health != MAGIC_JUNK) && (self->flags & MF_INBOUNCE)) { // Bounce self->health = MAGIC_JUNK; @@ -494,6 +518,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MaceBallImpact) self->gravity = FRACUNIT; S_Sound (self, CHAN_BODY, "weapons/macehit", 1, ATTN_NORM); } + return 0; } //---------------------------------------------------------------------------- @@ -504,6 +529,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_MaceBallImpact) DEFINE_ACTION_FUNCTION(AActor, A_MaceBallImpact2) { + PARAM_ACTION_PROLOGUE; + AActor *tiny; angle_t angle; @@ -558,6 +585,7 @@ boom: self->BounceFlags = BOUNCE_None; self->gravity = FRACUNIT; } + return 0; } //---------------------------------------------------------------------------- @@ -568,20 +596,22 @@ boom: DEFINE_ACTION_FUNCTION(AActor, A_FireMacePL2) { + PARAM_ACTION_PROLOGUE; + AActor *mo; player_t *player; AActor *linetarget; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } mo = P_SpawnPlayerMissile (self, 0,0,0, RUNTIME_CLASS(AMaceFX4), self->angle, &linetarget); if (mo) @@ -596,6 +626,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMacePL2) } } S_Sound (self, CHAN_WEAPON, "weapons/maceshoot", 1, ATTN_NORM); + return 0; } //---------------------------------------------------------------------------- @@ -606,6 +637,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMacePL2) DEFINE_ACTION_FUNCTION(AActor, A_DeathBallImpact) { + PARAM_ACTION_PROLOGUE; + int i; AActor *target; angle_t angle = 0; @@ -615,7 +648,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeathBallImpact) if ((self->z <= self->floorz) && P_HitFloor (self)) { // Landed in some sort of liquid self->Destroy (); - return; + return 0; } if (self->flags & MF_INBOUNCE) { @@ -687,6 +720,7 @@ boom: self->gravity = FRACUNIT; S_Sound (self, CHAN_BODY, "weapons/maceexplode", 1, ATTN_NORM); } + return 0; } @@ -762,20 +796,22 @@ int ARipper::DoSpecialDamage (AActor *target, int damage) DEFINE_ACTION_FUNCTION(AActor, A_FireBlasterPL1) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int damage; player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } angle_t pitch = P_BulletSlope(self); damage = pr_fb1.HitDice (4); @@ -786,6 +822,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireBlasterPL1) } P_LineAttack (self, angle, PLAYERMISSILERANGE, pitch, damage, NAME_None, "BlasterPuff"); S_Sound (self, CHAN_WEAPON, "weapons/blastershoot", 1, ATTN_NORM); + return 0; } //---------------------------------------------------------------------------- @@ -796,6 +833,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireBlasterPL1) DEFINE_ACTION_FUNCTION(AActor, A_SpawnRippers) { + PARAM_ACTION_PROLOGUE; + int i; angle_t angle; AActor *ripper; @@ -811,6 +850,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnRippers) ripper->vely = FixedMul (ripper->Speed, finesine[angle]); P_CheckMissileSpawn (ripper); } + return 0; } // --- Skull rod ------------------------------------------------------------ @@ -883,19 +923,21 @@ void ARainTracker::Serialize (FArchive &arc) DEFINE_ACTION_FUNCTION(AActor, A_FireSkullRodPL1) { + PARAM_ACTION_PROLOGUE; + AActor *mo; player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } mo = P_SpawnPlayerMissile (self, PClass::FindClass("HornRodFX1")); // Randomize the first frame @@ -903,6 +945,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSkullRodPL1) { mo->SetState (mo->state->GetNextState()); } + return 0; } //---------------------------------------------------------------------------- @@ -916,19 +959,21 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSkullRodPL1) DEFINE_ACTION_FUNCTION(AActor, A_FireSkullRodPL2) { + PARAM_ACTION_PROLOGUE; + player_t *player; AActor *MissileActor; AActor *linetarget; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } P_SpawnPlayerMissile (self, 0,0,0, RUNTIME_CLASS(AHornRodFX2), self->angle, &linetarget, &MissileActor); // Use MissileActor instead of the return value from @@ -943,6 +988,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSkullRodPL2) } S_Sound (MissileActor, CHAN_WEAPON, "weapons/hornrodpowshoot", 1, ATTN_NORM); } + return 0; } //---------------------------------------------------------------------------- @@ -953,11 +999,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSkullRodPL2) DEFINE_ACTION_FUNCTION(AActor, A_AddPlayerRain) { + PARAM_ACTION_PROLOGUE; + ARainTracker *tracker; if (self->target == NULL || self->target->health <= 0) { // Shooter is dead or nonexistant - return; + return 0; } tracker = self->target->FindInventory<ARainTracker> (); @@ -1000,6 +1048,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_AddPlayerRain) tracker->Rain1 = self; } self->special1 = S_FindSound ("misc/rain"); + return 0; } //---------------------------------------------------------------------------- @@ -1010,6 +1059,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_AddPlayerRain) DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm) { + PARAM_ACTION_PROLOGUE; + fixed_t x; fixed_t y; AActor *mo; @@ -1021,7 +1072,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm) if (self->target == NULL) { // Player left the game self->Destroy (); - return; + return 0; } tracker = self->target->FindInventory<ARainTracker> (); if (tracker != NULL) @@ -1036,11 +1087,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm) } } self->Destroy (); - return; + return 0; } if (pr_storm() < 25) { // Fudge rain frequency - return; + return 0; } x = self->x + ((pr_storm()&127) - 64) * FRACUNIT; y = self->y + ((pr_storm()&127) - 64) * FRACUNIT; @@ -1056,6 +1107,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm) { S_Sound (self, CHAN_BODY|CHAN_LOOP, self->special1, 1, ATTN_NORM); } + return 0; } //---------------------------------------------------------------------------- @@ -1066,6 +1118,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm) DEFINE_ACTION_FUNCTION(AActor, A_RainImpact) { + PARAM_ACTION_PROLOGUE; + if (self->z > self->floorz) { self->SetState (self->FindState("NotFloor")); @@ -1074,6 +1128,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RainImpact) { P_HitFloor (self); } + return 0; } //---------------------------------------------------------------------------- @@ -1084,7 +1139,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_RainImpact) DEFINE_ACTION_FUNCTION(AActor, A_HideInCeiling) { + PARAM_ACTION_PROLOGUE; + self->z = self->ceilingz + 4*FRACUNIT; + return 0; } // --- Phoenix Rod ---------------------------------------------------------- @@ -1168,25 +1226,28 @@ int APhoenixFX2::DoSpecialDamage (AActor *target, int damage) DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL1) { + PARAM_ACTION_PROLOGUE; + angle_t angle; player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } P_SpawnPlayerMissile (self, RUNTIME_CLASS(APhoenixFX1)); angle = self->angle + ANG180; angle >>= ANGLETOFINESHIFT; self->velx += FixedMul (4*FRACUNIT, finecosine[angle]); self->vely += FixedMul (4*FRACUNIT, finesine[angle]); + return 0; } //---------------------------------------------------------------------------- @@ -1197,6 +1258,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL1) DEFINE_ACTION_FUNCTION(AActor, A_PhoenixPuff) { + PARAM_ACTION_PROLOGUE; + AActor *puff; angle_t angle; @@ -1214,6 +1277,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PhoenixPuff) puff->velx = FixedMul (FRACUNIT*13/10, finecosine[angle]); puff->vely = FixedMul (FRACUNIT*13/10, finesine[angle]); puff->velz = 0; + return 0; } //---------------------------------------------------------------------------- @@ -1224,6 +1288,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_PhoenixPuff) DEFINE_ACTION_FUNCTION(AActor, A_InitPhoenixPL2) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { APhoenixRod *flamethrower = static_cast<APhoenixRod *> (self->player->ReadyWeapon); @@ -1232,6 +1298,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_InitPhoenixPL2) flamethrower->FlameCount = FLAME_THROWER_TICS; } } + return 0; } //---------------------------------------------------------------------------- @@ -1244,6 +1311,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_InitPhoenixPL2) DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL2) { + PARAM_ACTION_PROLOGUE; + AActor *mo; angle_t angle; fixed_t x, y, z; @@ -1254,7 +1323,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL2) if (NULL == (player = self->player)) { - return; + return 0; } soundid = "weapons/phoenixpowshoot"; @@ -1265,7 +1334,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL2) P_SetPsprite (player, ps_weapon, flamethrower->FindState("Powerdown")); player->refire = 0; S_StopSound (self, CHAN_WEAPON); - return; + return 0; } angle = self->angle; x = self->x + (pr_fp2.Random2() << 9); @@ -1284,6 +1353,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL2) S_Sound (self, CHAN_WEAPON|CHAN_LOOP, soundid, 1, ATTN_NORM); } P_CheckMissileSpawn (mo); + return 0; } //---------------------------------------------------------------------------- @@ -1294,19 +1364,22 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL2) DEFINE_ACTION_FUNCTION(AActor, A_ShutdownPhoenixPL2) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } S_StopSound (self, CHAN_WEAPON); AWeapon *weapon = player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } + return 0; } //---------------------------------------------------------------------------- @@ -1317,7 +1390,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_ShutdownPhoenixPL2) DEFINE_ACTION_FUNCTION(AActor, A_FlameEnd) { + PARAM_ACTION_PROLOGUE; + self->velz += FRACUNIT*3/2; + return 0; } //---------------------------------------------------------------------------- @@ -1328,6 +1404,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_FlameEnd) DEFINE_ACTION_FUNCTION(AActor, A_FloatPuff) { + PARAM_ACTION_PROLOGUE; + self->velz += FRACUNIT*18/10; + return 0; } diff --git a/src/g_heretic/a_ironlich.cpp b/src/g_heretic/a_ironlich.cpp index 61220f419..f21dc5208 100644 --- a/src/g_heretic/a_ironlich.cpp +++ b/src/g_heretic/a_ironlich.cpp @@ -59,6 +59,8 @@ int AWhirlwind::DoSpecialDamage (AActor *target, int damage) DEFINE_ACTION_FUNCTION(AActor, A_LichAttack) { + PARAM_ACTION_PROLOGUE; + int i; AActor *fire; AActor *baseFire; @@ -77,7 +79,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack) target = self->target; if (target == NULL) { - return; + return 0; } A_FaceTarget (self); if (self->CheckMeleeRange ()) @@ -85,7 +87,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack) int damage = pr_atk.HitDice (6); P_DamageMobj (target, self, self, damage, NAME_Melee); P_TraceBleed (damage, target, self); - return; + return 0; } dist = P_AproxDistance (self->x-target->x, self->y-target->y) > 8*64*FRACUNIT; @@ -133,6 +135,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack) S_Sound (self, CHAN_BODY, "ironlich/attack3", 1, ATTN_NORM); } } + return 0; } //---------------------------------------------------------------------------- @@ -143,13 +146,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack) DEFINE_ACTION_FUNCTION(AActor, A_WhirlwindSeek) { + PARAM_ACTION_PROLOGUE; + self->health -= 3; if (self->health < 0) { self->velx = self->vely = self->velz = 0; self->SetState (self->FindState(NAME_Death)); self->flags &= ~MF_MISSILE; - return; + return 0; } if ((self->special2 -= 3) < 0) { @@ -158,9 +163,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_WhirlwindSeek) } if (self->tracer && self->tracer->flags&MF_SHADOW) { - return; + return 0; } P_SeekerMissile (self, ANGLE_1*10, ANGLE_1*30); + return 0; } //---------------------------------------------------------------------------- @@ -171,6 +177,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_WhirlwindSeek) DEFINE_ACTION_FUNCTION(AActor, A_LichIceImpact) { + PARAM_ACTION_PROLOGUE; + int i; angle_t angle; AActor *shard; @@ -187,6 +195,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichIceImpact) shard->velz = -FRACUNIT*6/10; P_CheckMissileSpawn (shard); } + return 0; } //---------------------------------------------------------------------------- @@ -197,6 +206,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichIceImpact) DEFINE_ACTION_FUNCTION(AActor, A_LichFireGrow) { + PARAM_ACTION_PROLOGUE; + self->health--; self->z += 9*FRACUNIT; if (self->health == 0) @@ -204,5 +215,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichFireGrow) self->Damage = self->GetDefault()->Damage; self->SetState (self->FindState("NoGrow")); } + return 0; } diff --git a/src/g_heretic/a_knight.cpp b/src/g_heretic/a_knight.cpp index 2fb8a0ef4..d6a3d2760 100644 --- a/src/g_heretic/a_knight.cpp +++ b/src/g_heretic/a_knight.cpp @@ -21,6 +21,8 @@ static FRandom pr_knightatk ("KnightAttack"); DEFINE_ACTION_FUNCTION(AActor, A_DripBlood) { + PARAM_ACTION_PROLOGUE; + AActor *mo; fixed_t x, y; @@ -30,6 +32,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DripBlood) mo->velx = pr_dripblood.Random2 () << 10; mo->vely = pr_dripblood.Random2 () << 10; mo->gravity = FRACUNIT/8; + return 0; } //---------------------------------------------------------------------------- @@ -40,9 +43,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_DripBlood) DEFINE_ACTION_FUNCTION(AActor, A_KnightAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target) { - return; + return 0; } if (self->CheckMeleeRange ()) { @@ -50,16 +55,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_KnightAttack) P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (damage, self->target, self); S_Sound (self, CHAN_BODY, "hknight/melee", 1, ATTN_NORM); - return; + return 0; } // Throw axe S_Sound (self, CHAN_BODY, self->AttackSound, 1, ATTN_NORM); if (self->flags & MF_SHADOW || pr_knightatk () < 40) { // Red axe P_SpawnMissileZ (self, self->z + 36*FRACUNIT, self->target, PClass::FindClass("RedAxe")); - return; + return 0; } // Green axe P_SpawnMissileZ (self, self->z + 36*FRACUNIT, self->target, PClass::FindClass("KnightAxe")); + return 0; } diff --git a/src/g_heretic/a_wizard.cpp b/src/g_heretic/a_wizard.cpp index 119a1b1ef..69611546d 100644 --- a/src/g_heretic/a_wizard.cpp +++ b/src/g_heretic/a_wizard.cpp @@ -20,8 +20,11 @@ static FRandom pr_wizatk3 ("WizAtk3"); DEFINE_ACTION_FUNCTION(AActor, A_GhostOff) { + PARAM_ACTION_PROLOGUE; + self->RenderStyle = STYLE_Normal; self->flags3 &= ~MF3_GHOST; + return 0; } //---------------------------------------------------------------------------- @@ -32,8 +35,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_GhostOff) DEFINE_ACTION_FUNCTION(AActor, A_WizAtk1) { + PARAM_ACTION_PROLOGUE; + A_FaceTarget (self); CALL_ACTION(A_GhostOff, self); + return 0; } //---------------------------------------------------------------------------- @@ -44,10 +50,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_WizAtk1) DEFINE_ACTION_FUNCTION(AActor, A_WizAtk2) { + PARAM_ACTION_PROLOGUE; + A_FaceTarget (self); self->alpha = HR_SHADOW; self->RenderStyle = STYLE_Translucent; self->flags3 |= MF3_GHOST; + return 0; } //---------------------------------------------------------------------------- @@ -58,12 +67,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_WizAtk2) DEFINE_ACTION_FUNCTION(AActor, A_WizAtk3) { + PARAM_ACTION_PROLOGUE; + AActor *mo; CALL_ACTION(A_GhostOff, self); if (!self->target) { - return; + return 0; } S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); if (self->CheckMeleeRange()) @@ -71,7 +82,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_WizAtk3) int damage = pr_wizatk3.HitDice (4); P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (damage, self->target, self); - return; + return 0; } const PClass *fx = PClass::FindClass("WizardFX1"); mo = P_SpawnMissile (self, self->target, fx); @@ -80,4 +91,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_WizAtk3) P_SpawnMissileAngle(self, fx, mo->angle-(ANG45/8), mo->velz); P_SpawnMissileAngle(self, fx, mo->angle+(ANG45/8), mo->velz); } + return 0; } diff --git a/src/g_hexen/a_bats.cpp b/src/g_hexen/a_bats.cpp index c1674d218..c6d0389d9 100644 --- a/src/g_hexen/a_bats.cpp +++ b/src/g_hexen/a_bats.cpp @@ -27,17 +27,22 @@ static FRandom pr_batmove ("BatMove"); DEFINE_ACTION_FUNCTION(AActor, A_BatSpawnInit) { + PARAM_ACTION_PROLOGUE; + self->special1 = 0; // Frequency count + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_BatSpawn) { + PARAM_ACTION_PROLOGUE; + AActor *mo; int delta; angle_t angle; // Countdown until next spawn - if (self->special1-- > 0) return; + if (self->special1-- > 0) return 0; self->special1 = self->args[0]; // Reset frequency count delta = self->args[1]; @@ -51,11 +56,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_BatSpawn) mo->special2 = self->args[3]<<3; // Set lifetime mo->target = self; } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_BatMove) { + PARAM_ACTION_PROLOGUE; + angle_t newangle; if (self->special2 < 0) @@ -86,4 +94,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_BatMove) // Handle Z movement self->z = self->target->z + 2*FloatBobOffsets[self->args[0]]; self->args[0] = (self->args[0]+3)&63; + return 0; } diff --git a/src/g_hexen/a_bishop.cpp b/src/g_hexen/a_bishop.cpp index 1e4109748..22541a57a 100644 --- a/src/g_hexen/a_bishop.cpp +++ b/src/g_hexen/a_bishop.cpp @@ -24,9 +24,11 @@ static FRandom pr_pain ("BishopPainBlur"); DEFINE_ACTION_FUNCTION(AActor, A_BishopAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target) { - return; + return 0; } S_Sound (self, CHAN_BODY, self->AttackSound, 1, ATTN_NORM); if (self->CheckMeleeRange()) @@ -34,9 +36,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopAttack) int damage = pr_atk.HitDice (4); P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (damage, self->target, self); - return; + return 0; } self->special1 = (pr_atk() & 3) + 5; + return 0; } //============================================================================ @@ -48,13 +51,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopAttack) DEFINE_ACTION_FUNCTION(AActor, A_BishopAttack2) { + PARAM_ACTION_PROLOGUE; + AActor *mo; if (!self->target || !self->special1) { self->special1 = 0; self->SetState (self->SeeState); - return; + return 0; } mo = P_SpawnMissile (self, self->target, PClass::FindClass("BishopFX")); if (mo != NULL) @@ -63,6 +68,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopAttack2) mo->special2 = 16; // High word == x/y, Low word == z } self->special1--; + return 0; } //============================================================================ @@ -73,6 +79,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopAttack2) DEFINE_ACTION_FUNCTION(AActor, A_BishopMissileWeave) { + PARAM_ACTION_PROLOGUE; + fixed_t newX, newY; int weaveXY, weaveZ; int angle; @@ -92,6 +100,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopMissileWeave) weaveZ = (weaveZ + 2) & 63; self->z += FloatBobOffsets[weaveZ]; self->special2 = weaveZ + (weaveXY<<16); + return 0; } //============================================================================ @@ -102,14 +111,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopMissileWeave) DEFINE_ACTION_FUNCTION(AActor, A_BishopDecide) { + PARAM_ACTION_PROLOGUE; + if (pr_decide() < 220) { - return; + return 0; } else { self->SetState (self->FindState ("Blur")); - } + } + return 0; } //============================================================================ @@ -120,6 +132,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopDecide) DEFINE_ACTION_FUNCTION(AActor, A_BishopDoBlur) { + PARAM_ACTION_PROLOGUE; + self->special1 = (pr_doblur() & 3) + 3; // Random number of blurs if (pr_doblur() < 120) { @@ -134,6 +148,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopDoBlur) P_ThrustMobj (self, self->angle, 11*FRACUNIT); } S_Sound (self, CHAN_BODY, "BishopBlur", 1, ATTN_NORM); + return 0; } //============================================================================ @@ -144,6 +159,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopDoBlur) DEFINE_ACTION_FUNCTION(AActor, A_BishopSpawnBlur) { + PARAM_ACTION_PROLOGUE; + AActor *mo; if (!--self->special1) @@ -164,6 +181,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopSpawnBlur) { mo->angle = self->angle; } + return 0; } //============================================================================ @@ -174,9 +192,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopSpawnBlur) DEFINE_ACTION_FUNCTION(AActor, A_BishopChase) { + PARAM_ACTION_PROLOGUE; + self->z -= FloatBobOffsets[self->special2] >> 1; self->special2 = (self->special2 + 4) & 63; self->z += FloatBobOffsets[self->special2] >> 1; + return 0; } //============================================================================ @@ -187,6 +208,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopChase) DEFINE_ACTION_FUNCTION(AActor, A_BishopPuff) { + PARAM_ACTION_PROLOGUE; + AActor *mo; mo = Spawn ("BishopPuff", self->x, self->y, self->z + 40*FRACUNIT, ALLOW_REPLACE); @@ -194,6 +217,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopPuff) { mo->velz = FRACUNIT/2; } + return 0; } //============================================================================ @@ -204,12 +228,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopPuff) DEFINE_ACTION_FUNCTION(AActor, A_BishopPainBlur) { + PARAM_ACTION_PROLOGUE; + AActor *mo; if (pr_pain() < 64) { self->SetState (self->FindState ("Blur")); - return; + return 0; } fixed_t x = self->x + (pr_pain.Random2()<<12); fixed_t y = self->y + (pr_pain.Random2()<<12); @@ -219,4 +245,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopPainBlur) { mo->angle = self->angle; } + return 0; } diff --git a/src/g_hexen/a_centaur.cpp b/src/g_hexen/a_centaur.cpp index f7ba3b99f..ff79ae9fd 100644 --- a/src/g_hexen/a_centaur.cpp +++ b/src/g_hexen/a_centaur.cpp @@ -16,6 +16,8 @@ static FRandom pr_centaurdefend ("CentaurDefend"); DEFINE_ACTION_FUNCTION(AActor, A_CentaurDefend) { + PARAM_ACTION_PROLOGUE; + A_FaceTarget (self); if (self->CheckMeleeRange() && pr_centaurdefend() < 32) { @@ -24,4 +26,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_CentaurDefend) self->flags2&=~(MF2_REFLECTIVE|MF2_INVULNERABLE); self->SetState (self->MeleeState); } + return 0; } diff --git a/src/g_hexen/a_clericflame.cpp b/src/g_hexen/a_clericflame.cpp index 0fe482ede..2b62c8f90 100644 --- a/src/g_hexen/a_clericflame.cpp +++ b/src/g_hexen/a_clericflame.cpp @@ -69,20 +69,23 @@ void ACFlameMissile::Effect () DEFINE_ACTION_FUNCTION(AActor, A_CFlameAttack) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } P_SpawnPlayerMissile (self, RUNTIME_CLASS(ACFlameMissile)); S_Sound (self, CHAN_WEAPON, "ClericFlameFire", 1, ATTN_NORM); + return 0; } //============================================================================ @@ -93,11 +96,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_CFlameAttack) DEFINE_ACTION_FUNCTION(AActor, A_CFlamePuff) { + PARAM_ACTION_PROLOGUE; + self->renderflags &= ~RF_INVISIBLE; self->velx = 0; self->vely = 0; self->velz = 0; S_Sound (self, CHAN_BODY, "ClericFlameExplode", 1, ATTN_NORM); + return 0; } //============================================================================ @@ -108,6 +114,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_CFlamePuff) DEFINE_ACTION_FUNCTION(AActor, A_CFlameMissile) { + PARAM_ACTION_PROLOGUE; + int i; int an, an90; fixed_t dist; @@ -148,6 +156,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CFlameMissile) } self->SetState (self->SpawnState); } + return 0; } //============================================================================ @@ -158,10 +167,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_CFlameMissile) DEFINE_ACTION_FUNCTION(AActor, A_CFlameRotate) { + PARAM_ACTION_PROLOGUE; + int an; an = (self->angle+ANG90)>>ANGLETOFINESHIFT; self->velx = self->special1+FixedMul(FLAMEROTSPEED, finecosine[an]); self->vely = self->special2+FixedMul(FLAMEROTSPEED, finesine[an]); self->angle += ANG90/15; + return 0; } diff --git a/src/g_hexen/a_clericholy.cpp b/src/g_hexen/a_clericholy.cpp index 6ad6522c3..e45ed07b2 100644 --- a/src/g_hexen/a_clericholy.cpp +++ b/src/g_hexen/a_clericholy.cpp @@ -184,6 +184,8 @@ bool AHolySpirit::IsOkayToAttack (AActor *link) DEFINE_ACTION_FUNCTION(AActor, A_CHolyAttack2) { + PARAM_ACTION_PROLOGUE; + int j; int i; AActor *mo; @@ -229,6 +231,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolyAttack2) } SpawnSpiritTail (mo); } + return 0; } //============================================================================ @@ -261,24 +264,27 @@ void SpawnSpiritTail (AActor *spirit) DEFINE_ACTION_FUNCTION(AActor, A_CHolyAttack) { + PARAM_ACTION_PROLOGUE; + player_t *player; AActor *linetarget; if (NULL == (player = self->player)) { - return; + return 0; } ACWeapWraithverge *weapon = static_cast<ACWeapWraithverge *> (self->player->ReadyWeapon); if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } AActor * missile = P_SpawnPlayerMissile (self, 0,0,0, PClass::FindClass ("HolyMissile"), self->angle, &linetarget); if (missile != NULL) missile->tracer = linetarget; weapon->CHolyCount = 3; S_Sound (self, CHAN_WEAPON, "HolySymbolFire", 1, ATTN_NORM); + return 0; } //============================================================================ @@ -289,6 +295,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolyAttack) DEFINE_ACTION_FUNCTION(AActor, A_CHolyPalette) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { ACWeapWraithverge *weapon = static_cast<ACWeapWraithverge *> (self->player->ReadyWeapon); @@ -297,6 +305,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolyPalette) weapon->CHolyCount--; } } + return 0; } //============================================================================ @@ -372,6 +381,8 @@ static void CHolyTailRemove (AActor *actor) DEFINE_ACTION_FUNCTION(AActor, A_CHolyTail) { + PARAM_ACTION_PROLOGUE; + AActor *parent; parent = self->target; @@ -379,7 +390,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolyTail) if (parent == NULL || parent->health <= 0) // better check for health than current state - it's safer! { // Ghost removed, so remove all tail parts CHolyTailRemove (self); - return; + return 0; } else { @@ -391,6 +402,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolyTail) } CHolyTailFollow (self, 10*FRACUNIT); } + return 0; } //============================================================================ @@ -529,6 +541,8 @@ static void CHolyWeave (AActor *actor) DEFINE_ACTION_FUNCTION(AActor, A_CHolySeek) { + PARAM_ACTION_PROLOGUE; + self->health--; if (self->health <= 0) { @@ -537,7 +551,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolySeek) self->velz = 0; self->SetState (self->FindState(NAME_Death)); self->tics -= pr_holyseek()&3; - return; + return 0; } if (self->tracer) { @@ -549,6 +563,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolySeek) } } CHolyWeave (self); + return 0; } //============================================================================ @@ -559,6 +574,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolySeek) DEFINE_ACTION_FUNCTION(AActor, A_CHolyCheckScream) { + PARAM_ACTION_PROLOGUE; + CALL_ACTION(A_CHolySeek, self); if (pr_checkscream() < 20) { @@ -568,6 +585,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolyCheckScream) { CHolyFindTarget(self); } + return 0; } //============================================================================ @@ -579,10 +597,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolyCheckScream) DEFINE_ACTION_FUNCTION(AActor, A_ClericAttack) { - if (!self->target) return; + PARAM_ACTION_PROLOGUE; + + if (!self->target) return 0; AActor * missile = P_SpawnMissileZ (self, self->z + 40*FRACUNIT, self->target, PClass::FindClass ("HolyMissile")); if (missile != NULL) missile->tracer = NULL; // No initial target S_Sound (self, CHAN_WEAPON, "HolySymbolFire", 1, ATTN_NORM); + return 0; } diff --git a/src/g_hexen/a_clericmace.cpp b/src/g_hexen/a_clericmace.cpp index d834dcd1b..cb9cc1b7b 100644 --- a/src/g_hexen/a_clericmace.cpp +++ b/src/g_hexen/a_clericmace.cpp @@ -17,6 +17,8 @@ static FRandom pr_maceatk ("CMaceAttack"); DEFINE_ACTION_FUNCTION(AActor, A_CMaceAttack) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int damage; int slope; @@ -26,7 +28,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CMaceAttack) if (NULL == (player = self->player)) { - return; + return 0; } damage = 25+(pr_maceatk()&15); @@ -60,5 +62,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_CMaceAttack) slope = P_AimLineAttack (player->mo, angle, MELEERANGE, &linetarget); P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff")); macedone: - return; + return 0; } diff --git a/src/g_hexen/a_clericstaff.cpp b/src/g_hexen/a_clericstaff.cpp index 220dc55e7..476560e8f 100644 --- a/src/g_hexen/a_clericstaff.cpp +++ b/src/g_hexen/a_clericstaff.cpp @@ -46,6 +46,8 @@ int ACStaffMissile::DoSpecialDamage (AActor *target, int damage) DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) { + PARAM_ACTION_PROLOGUE; + AActor *pmo; int damage; int newLife; @@ -57,7 +59,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; @@ -107,6 +109,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) break; } } + return 0; } //============================================================================ @@ -117,19 +120,21 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) DEFINE_ACTION_FUNCTION(AActor, A_CStaffAttack) { + PARAM_ACTION_PROLOGUE; + AActor *mo; player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } mo = P_SpawnPlayerMissile (self, RUNTIME_CLASS(ACStaffMissile), self->angle-(ANG45/15)); if (mo) @@ -142,6 +147,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffAttack) mo->special2 = 0; } S_Sound (self, CHAN_WEAPON, "ClericCStaffFire", 1, ATTN_NORM); + return 0; } //============================================================================ @@ -152,6 +158,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffAttack) DEFINE_ACTION_FUNCTION(AActor, A_CStaffMissileSlither) { + PARAM_ACTION_PROLOGUE; + fixed_t newX, newY; int weaveXY; int angle; @@ -165,6 +173,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffMissileSlither) newY += FixedMul(finesine[angle], FloatBobOffsets[weaveXY]); P_TryMove (self, newX, newY, true); self->special2 = weaveXY; + return 0; } //============================================================================ @@ -175,7 +184,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffMissileSlither) DEFINE_ACTION_FUNCTION(AActor, A_CStaffInitBlink) { + PARAM_ACTION_PROLOGUE; + self->special1 = (pr_blink()>>1)+20; + return 0; } //============================================================================ @@ -186,6 +198,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffInitBlink) DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheckBlink) { + PARAM_ACTION_PROLOGUE; + if (self->player && self->player->ReadyWeapon) { if (!--self->special1) @@ -198,4 +212,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheckBlink) DoReadyWeapon(self); } } + return 0; } diff --git a/src/g_hexen/a_dragon.cpp b/src/g_hexen/a_dragon.cpp index 0c5ea81b5..87f58f196 100644 --- a/src/g_hexen/a_dragon.cpp +++ b/src/g_hexen/a_dragon.cpp @@ -164,6 +164,8 @@ static void DragonSeek (AActor *actor, angle_t thresh, angle_t turnMax) DEFINE_ACTION_FUNCTION(AActor, A_DragonInitFlight) { + PARAM_ACTION_PROLOGUE; + FActorIterator iterator (self->tid); do @@ -172,10 +174,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonInitFlight) if (self->tracer == NULL) { self->SetState (self->SpawnState); - return; + return 0; } } while (self->tracer == self); self->RemoveFromHash (); + return 0; } //============================================================================ @@ -186,6 +189,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonInitFlight) DEFINE_ACTION_FUNCTION(AActor, A_DragonFlight) { + PARAM_ACTION_PROLOGUE; + angle_t angle; DragonSeek (self, 4*ANGLE_1, 8*ANGLE_1); @@ -194,7 +199,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonFlight) if(!(self->target->flags&MF_SHOOTABLE)) { // target died self->target = NULL; - return; + return 0; } angle = R_PointToAngle2(self->x, self->y, self->target->x, self->target->y); @@ -215,6 +220,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonFlight) { P_LookForPlayers (self, true, NULL); } + return 0; } //============================================================================ @@ -225,6 +231,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonFlight) DEFINE_ACTION_FUNCTION(AActor, A_DragonFlap) { + PARAM_ACTION_PROLOGUE; + CALL_ACTION(A_DragonFlight, self); if (pr_dragonflap() < 240) { @@ -234,6 +242,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonFlap) { self->PlayActiveSound (); } + return 0; } //============================================================================ @@ -244,7 +253,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonFlap) DEFINE_ACTION_FUNCTION(AActor, A_DragonAttack) { - P_SpawnMissile (self, self->target, PClass::FindClass ("DragonFireball")); + PARAM_ACTION_PROLOGUE; + + P_SpawnMissile (self, self->target, PClass::FindClass ("DragonFireball")); + return 0; } //============================================================================ @@ -255,6 +267,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonAttack) DEFINE_ACTION_FUNCTION(AActor, A_DragonFX2) { + PARAM_ACTION_PROLOGUE; + AActor *mo; int i; int delay; @@ -272,7 +286,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonFX2) mo->tics = delay+(pr_dragonfx2()&3)*i*2; mo->target = self->target; } - } + } + return 0; } //============================================================================ @@ -283,11 +298,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonFX2) DEFINE_ACTION_FUNCTION(AActor, A_DragonPain) { + PARAM_ACTION_PROLOGUE; + CALL_ACTION(A_Pain, self); if (!self->tracer) { // no destination spot yet self->SetState (self->SeeState); } + return 0; } //============================================================================ @@ -298,8 +316,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonPain) DEFINE_ACTION_FUNCTION(AActor, A_DragonCheckCrash) { + PARAM_ACTION_PROLOGUE; + if (self->z <= self->floorz) { self->SetState (self->FindState ("Crash")); } + return 0; } diff --git a/src/g_hexen/a_fighteraxe.cpp b/src/g_hexen/a_fighteraxe.cpp index 281d20c2c..8c5e8c540 100644 --- a/src/g_hexen/a_fighteraxe.cpp +++ b/src/g_hexen/a_fighteraxe.cpp @@ -70,11 +70,13 @@ FState *AFWeapAxe::GetAtkState (bool hold) DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckReady) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } if (player->ReadyWeapon->Ammo1->Amount) { @@ -84,6 +86,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckReady) { DoReadyWeapon(self); } + return 0; } //============================================================================ @@ -94,11 +97,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckReady) DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckReadyG) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } if (player->ReadyWeapon->Ammo1->Amount <= 0) { @@ -108,6 +113,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckReadyG) { DoReadyWeapon(self); } + return 0; } //============================================================================ @@ -118,11 +124,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckReadyG) DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckUp) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } if (player->ReadyWeapon->Ammo1->Amount) { @@ -132,6 +140,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckUp) { CALL_ACTION(A_Raise, self); } + return 0; } //============================================================================ @@ -142,11 +151,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckUp) DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckUpG) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } if (player->ReadyWeapon->Ammo1->Amount <= 0) { @@ -156,6 +167,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckUpG) { CALL_ACTION(A_Raise, self); } + return 0; } //============================================================================ @@ -166,16 +178,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckUpG) DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckAtk) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } if (player->ReadyWeapon->Ammo1->Amount) { P_SetPsprite (player, ps_weapon, player->ReadyWeapon->FindState ("FireGlow")); } + return 0; } //============================================================================ @@ -186,6 +201,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckAtk) DEFINE_ACTION_FUNCTION(AActor, A_FAxeAttack) { + PARAM_ACTION_PROLOGUE; + angle_t angle; fixed_t power; int damage; @@ -199,7 +216,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeAttack) if (NULL == (player = self->player)) { - return; + return 0; } AActor *pmo=player->mo; @@ -271,6 +288,6 @@ axedone: } } } - return; + return 0; } diff --git a/src/g_hexen/a_fighterhammer.cpp b/src/g_hexen/a_fighterhammer.cpp index edb618bea..2116ec665 100644 --- a/src/g_hexen/a_fighterhammer.cpp +++ b/src/g_hexen/a_fighterhammer.cpp @@ -27,6 +27,8 @@ extern void AdjustPlayerAngle (AActor *pmo, AActor *linetarget); DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int damage; fixed_t power; @@ -37,7 +39,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack) if (NULL == (player = self->player)) { - return; + return 0; } AActor *pmo=player->mo; @@ -91,7 +93,7 @@ hammerdone: { pmo->special1 = false; } - return; + return 0; } //============================================================================ @@ -102,27 +104,30 @@ hammerdone: DEFINE_ACTION_FUNCTION(AActor, A_FHammerThrow) { + PARAM_ACTION_PROLOGUE; + AActor *mo; player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } if (!player->mo->special1) { - return; + return 0; } AWeapon *weapon = player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire, false)) - return; + return 0; } mo = P_SpawnPlayerMissile (player->mo, PClass::FindClass ("HammerMissile")); if (mo) { mo->special1 = 0; - } + } + return 0; } diff --git a/src/g_hexen/a_fighterplayer.cpp b/src/g_hexen/a_fighterplayer.cpp index ba1bc9e82..afa15d702 100644 --- a/src/g_hexen/a_fighterplayer.cpp +++ b/src/g_hexen/a_fighterplayer.cpp @@ -134,6 +134,8 @@ void AdjustPlayerAngle (AActor *pmo, AActor *linetarget) DEFINE_ACTION_FUNCTION(AActor, A_FPunchAttack) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int damage; int slope; @@ -145,7 +147,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FPunchAttack) if (NULL == (player = self->player)) { - return; + return 0; } APlayerPawn *pmo = player->mo; @@ -207,6 +209,6 @@ punchdone: P_SetPsprite (player, ps_weapon, player->ReadyWeapon->FindState ("Fire2")); S_Sound (pmo, CHAN_VOICE, "*fistgrunt", 1, ATTN_NORM); } - return; + return 0; } diff --git a/src/g_hexen/a_fighterquietus.cpp b/src/g_hexen/a_fighterquietus.cpp index dc930a34f..6a73b7eca 100644 --- a/src/g_hexen/a_fighterquietus.cpp +++ b/src/g_hexen/a_fighterquietus.cpp @@ -63,10 +63,10 @@ bool AFighterWeaponPiece::TryPickup (AActor *&toucher) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DropWeaponPieces) { - ACTION_PARAM_START(3); - ACTION_PARAM_CLASS(p1, 0); - ACTION_PARAM_CLASS(p2, 1); - ACTION_PARAM_CLASS(p3, 2); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS(p1, AActor); + PARAM_CLASS(p2, AActor); + PARAM_CLASS(p3, AActor); for (int i = 0, j = 0, fineang = 0; i < 3; ++i) { @@ -85,6 +85,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DropWeaponPieces) } } } + return 0; } @@ -117,17 +118,19 @@ int AFSwordMissile::DoSpecialDamage(AActor *victim, AActor *source, int damage) DEFINE_ACTION_FUNCTION(AActor, A_FSwordAttack) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } P_SpawnPlayerMissile (self, 0, 0, -10*FRACUNIT, RUNTIME_CLASS(AFSwordMissile), self->angle+ANGLE_45/4); P_SpawnPlayerMissile (self, 0, 0, -5*FRACUNIT, RUNTIME_CLASS(AFSwordMissile), self->angle+ANGLE_45/8); @@ -135,6 +138,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FSwordAttack) P_SpawnPlayerMissile (self, 0, 0, 5*FRACUNIT, RUNTIME_CLASS(AFSwordMissile), self->angle-ANGLE_45/8); P_SpawnPlayerMissile (self, 0, 0, 10*FRACUNIT, RUNTIME_CLASS(AFSwordMissile), self->angle-ANGLE_45/4); S_Sound (self, CHAN_WEAPON, "FighterSwordFire", 1, ATTN_NORM); + return 0; } //============================================================================ @@ -145,6 +149,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FSwordAttack) DEFINE_ACTION_FUNCTION(AActor, A_FSwordFlames) { + PARAM_ACTION_PROLOGUE; + int i; for (i = 1+(pr_fswordflame()&3); i; i--) @@ -154,6 +160,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FSwordFlames) fixed_t z = self->z+((pr_fswordflame()-128)<<11); Spawn ("FSwordFlame", x, y, z, ALLOW_REPLACE); } + return 0; } //============================================================================ @@ -164,7 +171,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_FSwordFlames) DEFINE_ACTION_FUNCTION(AActor, A_FighterAttack) { - if (!self->target) return; + PARAM_ACTION_PROLOGUE; + + if (!self->target) return 0; angle_t angle = self->angle; @@ -174,5 +183,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_FighterAttack) P_SpawnMissileAngle (self, RUNTIME_CLASS(AFSwordMissile), angle-ANG45/8, 0); P_SpawnMissileAngle (self, RUNTIME_CLASS(AFSwordMissile), angle-ANG45/4, 0); S_Sound (self, CHAN_WEAPON, "FighterSwordFire", 1, ATTN_NORM); + return 0; } diff --git a/src/g_hexen/a_firedemon.cpp b/src/g_hexen/a_firedemon.cpp index d0366fdf0..d13b6600e 100644 --- a/src/g_hexen/a_firedemon.cpp +++ b/src/g_hexen/a_firedemon.cpp @@ -81,11 +81,14 @@ void A_FiredSpawnRock (AActor *actor) DEFINE_ACTION_FUNCTION(AActor, A_FiredRocks) { + PARAM_ACTION_PROLOGUE; + A_FiredSpawnRock (self); A_FiredSpawnRock (self); A_FiredSpawnRock (self); A_FiredSpawnRock (self); A_FiredSpawnRock (self); + return 0; } //============================================================================ @@ -96,11 +99,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredRocks) DEFINE_ACTION_FUNCTION(AActor, A_SmBounce) { + PARAM_ACTION_PROLOGUE; + // give some more velocity (x,y,&z) self->z = self->floorz + FRACUNIT; self->velz = (2*FRACUNIT) + (pr_smbounce() << 10); self->velx = pr_smbounce()%3<<FRACBITS; self->vely = pr_smbounce()%3<<FRACBITS; + return 0; } //============================================================================ @@ -111,10 +117,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_SmBounce) DEFINE_ACTION_FUNCTION(AActor, A_FiredAttack) { + PARAM_ACTION_PROLOGUE; + if (self->target == NULL) - return; + return 0; AActor *mo = P_SpawnMissile (self, self->target, PClass::FindClass ("FireDemonMissile")); if (mo) S_Sound (self, CHAN_BODY, "FireDemonAttack", 1, ATTN_NORM); + return 0; } //============================================================================ @@ -125,6 +134,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredAttack) DEFINE_ACTION_FUNCTION(AActor, A_FiredChase) { + PARAM_ACTION_PROLOGUE; + int weaveindex = self->special1; AActor *target = self->target; angle_t ang; @@ -146,7 +157,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredChase) if(!self->target || !(self->target->flags&MF_SHOOTABLE)) { // Invalid target P_LookForPlayers (self,true, NULL); - return; + return 0; } // Strafe @@ -194,7 +205,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredChase) { self->SetState (self->MissileState); self->flags |= MF_JUSTATTACKED; - return; + return 0; } } else @@ -207,6 +218,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredChase) { self->PlayActiveSound (); } + return 0; } //============================================================================ @@ -217,6 +229,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredChase) DEFINE_ACTION_FUNCTION(AActor, A_FiredSplotch) { + PARAM_ACTION_PROLOGUE; + AActor *mo; mo = Spawn ("FireDemonSplotch1", self->x, self->y, self->z, ALLOW_REPLACE); @@ -233,4 +247,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredSplotch) mo->vely = (pr_firedemonsplotch() - 128) << 11; mo->velz = (pr_firedemonsplotch() << 10) + FRACUNIT*3; } + return 0; } diff --git a/src/g_hexen/a_flechette.cpp b/src/g_hexen/a_flechette.cpp index 884e356fd..4049c2ee6 100644 --- a/src/g_hexen/a_flechette.cpp +++ b/src/g_hexen/a_flechette.cpp @@ -297,6 +297,8 @@ int APoisonCloud::DoSpecialDamage (AActor *victim, int damage) DEFINE_ACTION_FUNCTION(AActor, A_PoisonBagInit) { + PARAM_ACTION_PROLOGUE; + AActor *mo; mo = Spawn<APoisonCloud> (self->x, self->y, self->z+28*FRACUNIT, ALLOW_REPLACE); @@ -304,6 +306,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PoisonBagInit) { mo->target = self->target; } + return 0; } //=========================================================================== @@ -314,14 +317,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_PoisonBagInit) DEFINE_ACTION_FUNCTION(AActor, A_PoisonBagCheck) { + PARAM_ACTION_PROLOGUE; + if (--self->special1 <= 0) { self->SetState (self->FindState ("Death")); } else { - return; + return 0; } + return 0; } //=========================================================================== @@ -332,12 +338,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_PoisonBagCheck) DEFINE_ACTION_FUNCTION(AActor, A_PoisonBagDamage) { + PARAM_ACTION_PROLOGUE; + int bobIndex; P_RadiusAttack (self, self->target, 4, 40, self->DamageType, true); bobIndex = self->special2; self->z += FloatBobOffsets[bobIndex]>>4; self->special2 = (bobIndex+1)&63; + return 0; } //=========================================================================== @@ -348,10 +357,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_PoisonBagDamage) DEFINE_ACTION_FUNCTION(AActor, A_CheckThrowBomb) { + PARAM_ACTION_PROLOGUE; + if (--self->health <= 0) { self->SetState (self->FindState(NAME_Death)); } + return 0; } //=========================================================================== @@ -362,6 +374,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckThrowBomb) DEFINE_ACTION_FUNCTION(AActor, A_CheckThrowBomb2) { + PARAM_ACTION_PROLOGUE; + // [RH] Check using actual velocity, although the velz < 2 check still stands //if (abs(self->velx) < FRACUNIT*3/2 && abs(self->vely) < FRACUNIT*3/2 // && self->velz < 2*FRACUNIT) @@ -376,4 +390,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckThrowBomb2) self->flags &= ~MF_MISSILE; } CALL_ACTION(A_CheckThrowBomb, self); + return 0; } diff --git a/src/g_hexen/a_fog.cpp b/src/g_hexen/a_fog.cpp index 34b1537ea..e755c6f10 100644 --- a/src/g_hexen/a_fog.cpp +++ b/src/g_hexen/a_fog.cpp @@ -27,6 +27,8 @@ static FRandom pr_fogspawn ("FogSpawn"); DEFINE_ACTION_FUNCTION(AActor, A_FogSpawn) { + PARAM_ACTION_PROLOGUE; + static const char *fogs[3] = { "FogPatchSmall", @@ -34,11 +36,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_FogSpawn) "FogPatchLarge" }; - AActor *mo=NULL; + AActor *mo = NULL; angle_t delta; - if (self->special1-- > 0) return; - + if (self->special1-- > 0) + { + return 0; + } self->special1 = self->args[2]; // Reset frequency count mo = Spawn (fogs[pr_fogspawn()%3], self->x, self->y, self->z, ALLOW_REPLACE); @@ -55,6 +59,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FogSpawn) mo->args[4] = 1; // Set to moving mo->special2 = pr_fogspawn()&63; } + return 0; } //========================================================================== @@ -65,16 +70,21 @@ DEFINE_ACTION_FUNCTION(AActor, A_FogSpawn) DEFINE_ACTION_FUNCTION(AActor, A_FogMove) { + PARAM_ACTION_PROLOGUE; + int speed = self->args[0]<<FRACBITS; angle_t angle; int weaveindex; - if (!(self->args[4])) return; + if (!self->args[4]) + { + return 0; + } if (self->args[3]-- <= 0) { self->SetStateNF (self->FindState(NAME_Death)); - return; + return 0; } if ((self->args[3] % 4) == 0) @@ -87,5 +97,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_FogMove) angle = self->angle>>ANGLETOFINESHIFT; self->velx = FixedMul(speed, finecosine[angle]); self->vely = FixedMul(speed, finesine[angle]); + return 0; } diff --git a/src/g_hexen/a_heresiarch.cpp b/src/g_hexen/a_heresiarch.cpp index 2107f2722..ecb27b5ed 100644 --- a/src/g_hexen/a_heresiarch.cpp +++ b/src/g_hexen/a_heresiarch.cpp @@ -231,6 +231,8 @@ void ASorcBall1::DoFireSpell () DEFINE_ACTION_FUNCTION(AActor, A_SorcSpinBalls) { + PARAM_ACTION_PROLOGUE; + AActor *mo; fixed_t z; @@ -252,6 +254,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcSpinBalls) if (mo) mo->target = self; mo = Spawn("SorcBall3", self->x, self->y, z, NO_REPLACE); if (mo) mo->target = self; + return 0; } @@ -263,11 +266,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcSpinBalls) DEFINE_ACTION_FUNCTION(AActor, A_SorcBallOrbit) { + PARAM_ACTION_PROLOGUE; + // [RH] If no parent, then die instead of crashing if (self->target == NULL) { self->SetState (self->FindState(NAME_Pain)); - return; + return 0; } ASorcBall *actor; @@ -287,7 +292,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcBallOrbit) if (actor->target->health <= 0) { actor->SetState (actor->FindState(NAME_Pain)); - return; + return 0; } baseangle = (angle_t)parent->special1; @@ -375,6 +380,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcBallOrbit) actor->SetOrigin (x, y, parent->z - parent->floorclip + parent->height); actor->floorz = parent->floorz; actor->ceilingz = parent->ceilingz; + return 0; } //============================================================================ @@ -387,8 +393,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcBallOrbit) DEFINE_ACTION_FUNCTION(AActor, A_SpeedBalls) { + PARAM_ACTION_PROLOGUE; + self->args[3] = SORC_ACCELERATE; // speed mode self->args[2] = SORCBALL_TERMINAL_SPEED; // target speed + return 0; } @@ -682,8 +691,11 @@ void A_SorcOffense2(AActor *actor) DEFINE_ACTION_FUNCTION(AActor, A_SorcBossAttack) { + PARAM_ACTION_PROLOGUE; + self->args[3] = SORC_ACCELERATE; self->args[2] = SORCBALL_INITIAL_SPEED; + return 0; } //============================================================================ @@ -696,6 +708,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcBossAttack) DEFINE_ACTION_FUNCTION(AActor, A_SpawnFizzle) { + PARAM_ACTION_PROLOGUE; + fixed_t x,y,z; fixed_t dist = 5*FRACUNIT; angle_t angle = self->angle >> ANGLETOFINESHIFT; @@ -718,6 +732,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnFizzle) mo->velz = FRACUNIT*2; } } + return 0; } @@ -731,8 +746,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnFizzle) DEFINE_ACTION_FUNCTION(AActor, A_SorcFX1Seek) { + PARAM_ACTION_PROLOGUE; + A_DoBounceCheck (self, "SorcererHeadScream"); P_SeekerMissile (self,ANGLE_1*2,ANGLE_1*6); + return 0; } @@ -754,6 +772,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcFX1Seek) // Split ball in two DEFINE_ACTION_FUNCTION(AActor, A_SorcFX2Split) { + PARAM_ACTION_PROLOGUE; + AActor *mo; mo = Spawn(self->GetClass(), self->x, self->y, self->z, NO_REPLACE); @@ -773,6 +793,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcFX2Split) mo->SetState (mo->FindState("Orbit")); } self->Destroy (); + return 0; } //============================================================================ @@ -785,6 +806,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcFX2Split) DEFINE_ACTION_FUNCTION(AActor, A_SorcFX2Orbit) { + PARAM_ACTION_PROLOGUE; + angle_t angle; fixed_t x,y,z; AActor *parent = self->target; @@ -793,7 +816,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcFX2Orbit) if (parent == NULL) { self->Destroy(); - return; + return 0; } fixed_t dist = parent->radius; @@ -841,6 +864,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcFX2Orbit) self->SetOrigin (x, y, z); self->floorz = parent->floorz; self->ceilingz = parent->ceilingz; + return 0; } //============================================================================ @@ -853,6 +877,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcFX2Orbit) DEFINE_ACTION_FUNCTION(AActor, A_SpawnBishop) { + PARAM_ACTION_PROLOGUE; + AActor *mo; mo = Spawn("Bishop", self->x, self->y, self->z, ALLOW_REPLACE); if (mo) @@ -869,6 +895,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnBishop) } } self->Destroy (); + return 0; } //============================================================================ @@ -879,8 +906,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnBishop) DEFINE_ACTION_FUNCTION(AActor, A_SorcererBishopEntry) { + PARAM_ACTION_PROLOGUE; + Spawn("SorcFX3Explosion", self->x, self->y, self->z, ALLOW_REPLACE); S_Sound (self, CHAN_VOICE, self->SeeSound, 1, ATTN_NORM); + return 0; } //============================================================================ @@ -893,10 +923,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcererBishopEntry) DEFINE_ACTION_FUNCTION(AActor, A_SorcFX4Check) { + PARAM_ACTION_PROLOGUE; + if (self->special2-- <= 0) { self->SetState (self->FindState(NAME_Death)); } + return 0; } //============================================================================ @@ -909,6 +942,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcFX4Check) DEFINE_ACTION_FUNCTION(AActor, A_SorcBallPop) { + PARAM_ACTION_PROLOGUE; + S_Sound (self, CHAN_BODY, "SorcererBallPop", 1, ATTN_NONE); self->flags &= ~MF_NOGRAVITY; self->gravity = FRACUNIT/8; @@ -918,6 +953,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcBallPop) self->special2 = 4*FRACUNIT; // Initial bounce factor self->args[4] = BOUNCE_TIME_UNIT; // Bounce time unit self->args[3] = 5; // Bounce time in seconds + return 0; } //============================================================================ @@ -950,5 +986,8 @@ void A_DoBounceCheck (AActor *self, const char *sound) DEFINE_ACTION_FUNCTION(AActor, A_BounceCheck) { + PARAM_ACTION_PROLOGUE; + A_DoBounceCheck (self, "SorcererBigBallExplode"); + return 0; } diff --git a/src/g_hexen/a_hexenspecialdecs.cpp b/src/g_hexen/a_hexenspecialdecs.cpp index a3fee8557..0edb27e25 100644 --- a/src/g_hexen/a_hexenspecialdecs.cpp +++ b/src/g_hexen/a_hexenspecialdecs.cpp @@ -55,6 +55,8 @@ void APottery1::HitFloor () DEFINE_ACTION_FUNCTION(AActor, A_PotteryExplode) { + PARAM_ACTION_PROLOGUE; + AActor *mo = NULL; int i; @@ -79,6 +81,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PotteryExplode) self->x, self->y, self->z, ALLOW_REPLACE); } } + return 0; } //============================================================================ @@ -89,8 +92,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_PotteryExplode) DEFINE_ACTION_FUNCTION(AActor, A_PotteryChooseBit) { + PARAM_ACTION_PROLOGUE; + self->SetState (self->FindState(NAME_Death) + 1 + 2*(pr_bit()%5)); self->tics = 256+(pr_bit()<<1); + return 0; } //============================================================================ @@ -101,6 +107,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_PotteryChooseBit) DEFINE_ACTION_FUNCTION(AActor, A_PotteryCheck) { + PARAM_ACTION_PROLOGUE; + int i; for(i = 0; i < MAXPLAYERS; i++) @@ -112,10 +120,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_PotteryCheck) pmo->y, self->x, self->y) - pmo->angle) <= ANGLE_45)) { // Previous state (pottery bit waiting state) self->SetState (self->state - 1); - return; + return 0; } } - } + } + return 0; } // Lynched corpse (no heart) ------------------------------------------------ @@ -143,10 +152,13 @@ void AZCorpseLynchedNoHeart::PostBeginPlay () DEFINE_ACTION_FUNCTION(AActor, A_CorpseBloodDrip) { + PARAM_ACTION_PROLOGUE; + if (pr_drip() <= 128) { Spawn ("CorpseBloodDrip", self->x, self->y, self->z + self->height/2, ALLOW_REPLACE); } + return 0; } //============================================================================ @@ -157,6 +169,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_CorpseBloodDrip) DEFINE_ACTION_FUNCTION(AActor, A_CorpseExplode) { + PARAM_ACTION_PROLOGUE; + AActor *mo; int i; @@ -182,6 +196,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CorpseExplode) } S_Sound (self, CHAN_BODY, self->DeathSound, 1, ATTN_IDLE); self->Destroy (); + return 0; } //============================================================================ @@ -192,6 +207,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_CorpseExplode) DEFINE_ACTION_FUNCTION(AActor, A_LeafSpawn) { + PARAM_ACTION_PROLOGUE; + AActor *mo; int i; @@ -208,6 +225,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LeafSpawn) mo->special1 = 0; } } + return 0; } //============================================================================ @@ -218,10 +236,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_LeafSpawn) DEFINE_ACTION_FUNCTION(AActor, A_LeafThrust) { + PARAM_ACTION_PROLOGUE; + if (pr_leafthrust() <= 96) { self->velz += (pr_leafthrust()<<9)+FRACUNIT; } + return 0; } //============================================================================ @@ -232,11 +253,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_LeafThrust) DEFINE_ACTION_FUNCTION(AActor, A_LeafCheck) { + PARAM_ACTION_PROLOGUE; + self->special1++; if (self->special1 >= 20) { self->SetState (NULL); - return; + return 0; } angle_t ang = self->target ? self->target->angle : self->angle; if (pr_leafcheck() > 64) @@ -245,12 +268,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_LeafCheck) { P_ThrustMobj (self, ang, (pr_leafcheck()<<9)+FRACUNIT); } - return; + return 0; } self->SetState (self->SpawnState + 7); self->velz = (pr_leafcheck()<<9)+FRACUNIT; P_ThrustMobj (self, ang, (pr_leafcheck()<<9)+2*FRACUNIT); self->flags |= MF_MISSILE; + return 0; } //=========================================================================== @@ -261,7 +285,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_LeafCheck) DEFINE_ACTION_FUNCTION(AActor, A_PoisonShroom) { + PARAM_ACTION_PROLOGUE; + self->tics = 128+(pr_shroom()<<1); + return 0; } //=========================================================================== @@ -272,6 +299,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_PoisonShroom) DEFINE_ACTION_FUNCTION(AActor, A_SoAExplode) { + PARAM_ACTION_PROLOGUE; + AActor *mo; int i; @@ -299,6 +328,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SoAExplode) } S_Sound (self, CHAN_BODY, self->DeathSound, 1, ATTN_NORM); self->Destroy (); + return 0; } // Bell --------------------------------------------------------------------- @@ -328,6 +358,8 @@ void AZBell::Activate (AActor *activator) DEFINE_ACTION_FUNCTION(AActor, A_BellReset1) { + PARAM_ACTION_PROLOGUE; + self->flags |= MF_NOGRAVITY; self->height <<= 2; if (self->special) @@ -336,6 +368,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BellReset1) self->args[1], self->args[2], self->args[3], self->args[4]); self->special = 0; } + return 0; } //=========================================================================== @@ -346,8 +379,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_BellReset1) DEFINE_ACTION_FUNCTION(AActor, A_BellReset2) { + PARAM_ACTION_PROLOGUE; + self->flags |= MF_SHOOTABLE; self->flags &= ~MF_CORPSE; self->health = 5; + return 0; } diff --git a/src/g_hexen/a_iceguy.cpp b/src/g_hexen/a_iceguy.cpp index 2d908f974..f43a76122 100644 --- a/src/g_hexen/a_iceguy.cpp +++ b/src/g_hexen/a_iceguy.cpp @@ -26,6 +26,8 @@ static const char *WispTypes[2] = DEFINE_ACTION_FUNCTION(AActor, A_IceGuyLook) { + PARAM_ACTION_PROLOGUE; + fixed_t dist; fixed_t an; @@ -40,6 +42,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceGuyLook) self->y+FixedMul(dist, finesine[an]), self->z+60*FRACUNIT, ALLOW_REPLACE); } + return 0; } //============================================================================ @@ -50,11 +53,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceGuyLook) DEFINE_ACTION_FUNCTION(AActor, A_IceGuyChase) { + PARAM_ACTION_PROLOGUE; + fixed_t dist; fixed_t an; AActor *mo; - A_Chase (self); + A_Chase (stack, self); if (pr_iceguychase() < 128) { dist = ((pr_iceguychase()-128)*self->radius)>>7; @@ -72,6 +77,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceGuyChase) mo->target = self; } } + return 0; } //============================================================================ @@ -82,11 +88,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceGuyChase) DEFINE_ACTION_FUNCTION(AActor, A_IceGuyAttack) { + PARAM_ACTION_PROLOGUE; + fixed_t an; if(!self->target) { - return; + return 0; } an = (self->angle+ANG90)>>ANGLETOFINESHIFT; P_SpawnMissileXYZ(self->x+FixedMul(self->radius>>1, @@ -99,6 +107,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceGuyAttack) finesine[an]), self->z+40*FRACUNIT, self, self->target, PClass::FindClass ("IceGuyFX")); S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); + return 0; } //============================================================================ @@ -109,11 +118,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceGuyAttack) DEFINE_ACTION_FUNCTION(AActor, A_IceGuyDie) { + PARAM_ACTION_PROLOGUE; + self->velx = 0; self->vely = 0; self->velz = 0; self->height = self->GetDefault()->height; CALL_ACTION(A_FreezeDeathChunks, self); + return 0; } //============================================================================ @@ -124,6 +136,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceGuyDie) DEFINE_ACTION_FUNCTION(AActor, A_IceGuyMissileExplode) { + PARAM_ACTION_PROLOGUE; + AActor *mo; int i; @@ -136,5 +150,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceGuyMissileExplode) mo->target = self->target; } } + return 0; } diff --git a/src/g_hexen/a_korax.cpp b/src/g_hexen/a_korax.cpp index 6f67cd6bd..a1f729865 100644 --- a/src/g_hexen/a_korax.cpp +++ b/src/g_hexen/a_korax.cpp @@ -89,6 +89,8 @@ extern void SpawnSpiritTail (AActor *spirit); DEFINE_ACTION_FUNCTION(AActor, A_KoraxChase) { + PARAM_ACTION_PROLOGUE; + AActor *spot; if ((!self->special2) && (self->health <= (self->SpawnHealth()/2))) @@ -103,10 +105,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxChase) P_StartScript (self, NULL, 249, NULL, 0, 0, 0, 0, 0, false); self->special2 = 1; // Don't run again - return; + return 0; } - if (!self->target) return; + if (self->target == NULL) + { + return 0; + } if (pr_koraxchase()<30) { self->SetState (self->MissileState); @@ -140,6 +145,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxChase) } } } + return 0; } //============================================================================ @@ -150,6 +156,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxChase) DEFINE_ACTION_FUNCTION(AActor, A_KoraxBonePop) { + PARAM_ACTION_PROLOGUE; + AActor *mo; int i; @@ -161,6 +169,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxBonePop) } P_StartScript (self, NULL, 255, NULL, 0, 0, 0, 0, false, false); // Death script + return 0; } //============================================================================ @@ -190,6 +199,8 @@ void KSpiritInit (AActor *spirit, AActor *korax) DEFINE_ACTION_FUNCTION(AActor, A_KoraxDecide) { + PARAM_ACTION_PROLOGUE; + if (pr_koraxdecide()<220) { self->SetState (self->FindState("Attack")); @@ -198,6 +209,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxDecide) { self->SetState (self->FindState("Command")); } + return 0; } //============================================================================ @@ -208,6 +220,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxDecide) DEFINE_ACTION_FUNCTION(AActor, A_KoraxMissile) { + PARAM_ACTION_PROLOGUE; + static const struct { const char *type, *sound; } choices[6] = { { "WraithFX1", "WraithMissileFire" }, @@ -236,6 +250,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxMissile) { KoraxFire (self, info, i); } + return 0; } //============================================================================ @@ -248,6 +263,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxMissile) DEFINE_ACTION_FUNCTION(AActor, A_KoraxCommand) { + PARAM_ACTION_PROLOGUE; + fixed_t x,y,z; angle_t ang; int numcommands; @@ -272,6 +289,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxCommand) P_StartScript (self, NULL, 250+(pr_koraxcommand()%numcommands), NULL, 0, 0, 0, 0, false, false); + return 0; } //============================================================================ @@ -329,6 +347,8 @@ void KoraxFire (AActor *actor, const PClass *type, int arm) DEFINE_ACTION_FUNCTION(AActor, A_KSpiritWeave) { + PARAM_ACTION_PROLOGUE; + fixed_t newX, newY; int weaveXY, weaveZ; int angle; @@ -350,6 +370,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KSpiritWeave) weaveZ = (weaveZ+(pr_kspiritweave()%5))&63; self->z += FloatBobOffsets[weaveZ]<<1; self->special2 = weaveZ+(weaveXY<<16); + return 0; } //============================================================================ @@ -430,6 +451,8 @@ void A_KSpiritSeeker (AActor *actor, angle_t thresh, angle_t turnMax) DEFINE_ACTION_FUNCTION(AActor, A_KSpiritRoam) { + PARAM_ACTION_PROLOGUE; + if (self->health-- <= 0) { S_Sound (self, CHAN_VOICE, "SpiritDie", 1, ATTN_NORM); @@ -448,6 +471,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KSpiritRoam) S_Sound (self, CHAN_VOICE, "SpiritActive", 1, ATTN_NONE); } } + return 0; } //============================================================================ @@ -458,11 +482,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_KSpiritRoam) DEFINE_ACTION_FUNCTION(AActor, A_KBolt) { + PARAM_ACTION_PROLOGUE; + // Countdown lifetime if (self->special1-- <= 0) { self->Destroy (); } + return 0; } //============================================================================ @@ -473,6 +500,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_KBolt) DEFINE_ACTION_FUNCTION(AActor, A_KBoltRaise) { + PARAM_ACTION_PROLOGUE; + AActor *mo; fixed_t z; @@ -491,6 +520,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KBoltRaise) { // Maybe cap it off here } + return 0; } //============================================================================ diff --git a/src/g_hexen/a_magecone.cpp b/src/g_hexen/a_magecone.cpp index a80eae659..4e1ff7739 100644 --- a/src/g_hexen/a_magecone.cpp +++ b/src/g_hexen/a_magecone.cpp @@ -51,6 +51,8 @@ int AFrostMissile::DoSpecialDamage (AActor *victim, int damage) DEFINE_ACTION_FUNCTION(AActor, A_FireConePL1) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int damage; int slope; @@ -62,14 +64,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireConePL1) if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } S_Sound (self, CHAN_WEAPON, "MageShardsFire", 1, ATTN_NORM); @@ -99,6 +101,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireConePL1) mo->args[0] = 3; // Mark Initial shard as super damage } } + return 0; } //============================================================================ @@ -109,11 +112,16 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireConePL1) DEFINE_ACTION_FUNCTION(AActor, A_ShedShard) { + PARAM_ACTION_PROLOGUE; + AActor *mo; int spawndir = self->special1; int spermcount = self->special2; - if (spermcount <= 0) return; // No sperm left + if (spermcount <= 0) + { + return 0; // No sperm left + } self->special2 = 0; spermcount--; @@ -173,4 +181,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_ShedShard) mo->args[0] = (spermcount==3)?2:0; } } + return 0; } diff --git a/src/g_hexen/a_magelightning.cpp b/src/g_hexen/a_magelightning.cpp index 7231514b9..10c555e4c 100644 --- a/src/g_hexen/a_magelightning.cpp +++ b/src/g_hexen/a_magelightning.cpp @@ -126,11 +126,14 @@ int ALightningZap::SpecialMissileHit (AActor *thing) DEFINE_ACTION_FUNCTION(AActor, A_LightningReady) { + PARAM_ACTION_PROLOGUE; + DoReadyWeapon(self); if (pr_lightningready() < 160) { S_Sound (self, CHAN_WEAPON, "MageLightningReady", 1, ATTN_NORM); } + return 0; } //============================================================================ @@ -141,6 +144,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightningReady) DEFINE_ACTION_FUNCTION(AActor, A_LightningClip) { + PARAM_ACTION_PROLOGUE; + AActor *cMo; AActor *target = NULL; int zigZag; @@ -149,7 +154,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightningClip) { if (self->lastenemy == NULL) { - return; + return 0; } self->z = self->floorz; target = self->lastenemy->tracer; @@ -196,6 +201,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightningClip) P_ThrustMobj (self, self->angle, self->Speed>>1); } } + return 0; } @@ -207,6 +213,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightningClip) DEFINE_ACTION_FUNCTION(AActor, A_LightningZap) { + PARAM_ACTION_PROLOGUE; const PClass *lightning=PClass::FindClass((ENamedName) self->GetClass()->Meta.GetMetaInt (ACMETA_MissileName, NAME_None)); if (lightning == NULL) lightning = PClass::FindClass("LightningZap"); @@ -219,7 +226,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightningZap) if (self->health <= 0) { self->SetState (self->FindState(NAME_Death)); - return; + return 0; } if (self->flags3 & MF3_FLOORHUGGER) { @@ -251,6 +258,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightningZap) { S_Sound (self, CHAN_BODY, self->ActiveSound, 1, ATTN_NORM); } + return 0; } //============================================================================ @@ -261,9 +269,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightningZap) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MLightningAttack) { - ACTION_PARAM_START(2); - ACTION_PARAM_CLASS(floor, 0); - ACTION_PARAM_CLASS(ceiling, 1); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT(floor, AActor) { floor = PClass::FindClass("LightningFloor"); } + PARAM_CLASS_OPT(ceiling, AActor) { ceiling = PClass::FindClass("LightningCeiling"); } AActor *fmo, *cmo; @@ -291,6 +299,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MLightningAttack) weapon->DepleteAmmo (weapon->bAltFire); } } + return 0; } //============================================================================ @@ -301,6 +310,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MLightningAttack) DEFINE_ACTION_FUNCTION(AActor, A_ZapMimic) { + PARAM_ACTION_PROLOGUE; + AActor *mo; mo = self->lastenemy; @@ -316,6 +327,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ZapMimic) self->vely = mo->vely; } } + return 0; } //============================================================================ @@ -326,7 +338,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_ZapMimic) DEFINE_ACTION_FUNCTION(AActor, A_LastZap) { - const PClass *lightning=PClass::FindClass((ENamedName) self->GetClass()->Meta.GetMetaInt (ACMETA_MissileName, NAME_None)); + PARAM_ACTION_PROLOGUE; + + const PClass *lightning = PClass::FindClass(ENamedName(self->GetClass()->Meta.GetMetaInt(ACMETA_MissileName, NAME_None))); if (lightning == NULL) lightning = PClass::FindClass("LightningZap"); AActor *mo; @@ -338,6 +352,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LastZap) mo->velz = 40*FRACUNIT; mo->Damage = 0; } + return 0; } //============================================================================ @@ -348,6 +363,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_LastZap) DEFINE_ACTION_FUNCTION(AActor, A_LightningRemove) { + PARAM_ACTION_PROLOGUE; + AActor *mo; mo = self->lastenemy; @@ -356,4 +373,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightningRemove) mo->lastenemy = NULL; P_ExplodeMissile (mo, NULL, NULL); } + return 0; } diff --git a/src/g_hexen/a_magestaff.cpp b/src/g_hexen/a_magestaff.cpp index 76610f693..503d81a17 100644 --- a/src/g_hexen/a_magestaff.cpp +++ b/src/g_hexen/a_magestaff.cpp @@ -179,20 +179,22 @@ void MStaffSpawn (AActor *pmo, angle_t angle) DEFINE_ACTION_FUNCTION(AActor, A_MStaffAttack) { + PARAM_ACTION_PROLOGUE; + angle_t angle; player_t *player; AActor *linetarget; if (NULL == (player = self->player)) { - return; + return 0; } AMWeapBloodscourge *weapon = static_cast<AMWeapBloodscourge *> (self->player->ReadyWeapon); if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } angle = self->angle; @@ -211,6 +213,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MStaffAttack) MStaffSpawn (self, angle+ANGLE_1*5); S_Sound (self, CHAN_WEAPON, "MageStaffFire", 1, ATTN_NORM); weapon->MStaffCount = 3; + return 0; } //============================================================================ @@ -221,6 +224,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_MStaffAttack) DEFINE_ACTION_FUNCTION(AActor, A_MStaffPalette) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { AMWeapBloodscourge *weapon = static_cast<AMWeapBloodscourge *> (self->player->ReadyWeapon); @@ -229,6 +234,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MStaffPalette) weapon->MStaffCount--; } } + return 0; } //============================================================================ @@ -239,11 +245,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_MStaffPalette) DEFINE_ACTION_FUNCTION(AActor, A_MStaffTrack) { + PARAM_ACTION_PROLOGUE; + if ((self->tracer == 0) && (pr_mstafftrack()<50)) { self->tracer = P_RoughMonsterSearch (self, 10); } P_SeekerMissile (self, ANGLE_1*2, ANGLE_1*10); + return 0; } //============================================================================ @@ -299,13 +308,17 @@ void MStaffSpawn2 (AActor *actor, angle_t angle) DEFINE_ACTION_FUNCTION(AActor, A_MageAttack) { - if (!self->target) return; + PARAM_ACTION_PROLOGUE; + if (self->target == NULL) + { + return 0; + } angle_t angle; angle = self->angle; MStaffSpawn2 (self, angle); MStaffSpawn2 (self, angle-ANGLE_1*5); MStaffSpawn2 (self, angle+ANGLE_1*5); S_Sound (self, CHAN_WEAPON, "MageStaffFire", 1, ATTN_NORM); + return 0; } - diff --git a/src/g_hexen/a_magewand.cpp b/src/g_hexen/a_magewand.cpp index b5d2aaa0f..de29bf7d8 100644 --- a/src/g_hexen/a_magewand.cpp +++ b/src/g_hexen/a_magewand.cpp @@ -51,8 +51,11 @@ void AMageWandMissile::Effect () DEFINE_ACTION_FUNCTION(AActor, A_MWandAttack) { + PARAM_ACTION_PROLOGUE; + AActor *mo; mo = P_SpawnPlayerMissile (self, RUNTIME_CLASS(AMageWandMissile)); S_Sound (self, CHAN_WEAPON, "MageWandFire", 1, ATTN_NORM); + return 0; } diff --git a/src/g_hexen/a_pig.cpp b/src/g_hexen/a_pig.cpp index 21d2ab936..e75ef9921 100644 --- a/src/g_hexen/a_pig.cpp +++ b/src/g_hexen/a_pig.cpp @@ -60,6 +60,8 @@ void APigPlayer::MorphPlayerThink () DEFINE_ACTION_FUNCTION(AActor, A_SnoutAttack) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int damage; int slope; @@ -69,7 +71,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SnoutAttack) if (NULL == (player = self->player)) { - return; + return 0; } damage = 3+(pr_snoutattack()&3); @@ -85,6 +87,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SnoutAttack) S_Sound(player->mo, CHAN_VOICE, "PigAttack", 1, ATTN_NORM); } } + return 0; } //============================================================================ @@ -95,9 +98,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_SnoutAttack) DEFINE_ACTION_FUNCTION(AActor, A_PigPain) { + PARAM_ACTION_PROLOGUE; + CALL_ACTION(A_Pain, self); if (self->z <= self->floorz) { self->velz = FRACUNIT*7/2; } + return 0; } diff --git a/src/g_hexen/a_serpent.cpp b/src/g_hexen/a_serpent.cpp index b44a6175d..8cbf0e163 100644 --- a/src/g_hexen/a_serpent.cpp +++ b/src/g_hexen/a_serpent.cpp @@ -25,8 +25,11 @@ static FRandom pr_delaygib ("DelayGib"); DEFINE_ACTION_FUNCTION(AActor, A_SerpentUnHide) { + PARAM_ACTION_PROLOGUE; + self->renderflags &= ~RF_INVISIBLE; self->floorclip = 24*FRACUNIT; + return 0; } //============================================================================ @@ -37,8 +40,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentUnHide) DEFINE_ACTION_FUNCTION(AActor, A_SerpentHide) { + PARAM_ACTION_PROLOGUE; + self->renderflags |= RF_INVISIBLE; self->floorclip = 0; + return 0; } //============================================================================ @@ -50,7 +56,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentHide) DEFINE_ACTION_FUNCTION(AActor, A_SerpentRaiseHump) { + PARAM_ACTION_PROLOGUE; + self->floorclip -= 4*FRACUNIT; + return 0; } //============================================================================ @@ -61,7 +70,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentRaiseHump) DEFINE_ACTION_FUNCTION(AActor, A_SerpentLowerHump) { + PARAM_ACTION_PROLOGUE; + self->floorclip += 4*FRACUNIT; + return 0; } //============================================================================ @@ -74,21 +86,23 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentLowerHump) DEFINE_ACTION_FUNCTION(AActor, A_SerpentHumpDecide) { + PARAM_ACTION_PROLOGUE; + if (self->MissileState != NULL) { if (pr_serpenthump() > 30) { - return; + return 0; } else if (pr_serpenthump() < 40) { // Missile attack self->SetState (self->MeleeState); - return; + return 0; } } else if (pr_serpenthump() > 3) { - return; + return 0; } if (!self->CheckMeleeRange ()) { // The hump shouldn't occur when within melee range @@ -102,6 +116,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentHumpDecide) S_Sound (self, CHAN_BODY, "SerpentActive", 1, ATTN_NORM); } } + return 0; } //============================================================================ @@ -112,16 +127,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentHumpDecide) DEFINE_ACTION_FUNCTION(AActor, A_SerpentCheckForAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target) { - return; + return 0; } if (self->MissileState != NULL) { if (!self->CheckMeleeRange ()) { self->SetState (self->FindState ("Attack")); - return; + return 0; } } if (P_CheckMeleeRange2 (self)) @@ -139,6 +156,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentCheckForAttack) self->SetState (self->FindState ("Attack")); } } + return 0; } //============================================================================ @@ -149,14 +167,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentCheckForAttack) DEFINE_ACTION_FUNCTION(AActor, A_SerpentChooseAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target || self->CheckMeleeRange()) { - return; + return 0; } if (self->MissileState != NULL) { self->SetState (self->MissileState); } + return 0; } //============================================================================ @@ -167,9 +188,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentChooseAttack) DEFINE_ACTION_FUNCTION(AActor, A_SerpentMeleeAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target) { - return; + return 0; } if (self->CheckMeleeRange ()) { @@ -182,6 +205,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentMeleeAttack) { CALL_ACTION(A_SerpentCheckForAttack, self); } + return 0; } //============================================================================ @@ -192,6 +216,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentMeleeAttack) DEFINE_ACTION_FUNCTION(AActor, A_SerpentSpawnGibs) { + PARAM_ACTION_PROLOGUE; + AActor *mo; static const char *GibTypes[] = { @@ -213,6 +239,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentSpawnGibs) mo->floorclip = 6*FRACUNIT; } } + return 0; } //============================================================================ @@ -223,7 +250,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentSpawnGibs) DEFINE_ACTION_FUNCTION(AActor, A_FloatGib) { + PARAM_ACTION_PROLOGUE; + self->floorclip -= FRACUNIT; + return 0; } //============================================================================ @@ -234,7 +264,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_FloatGib) DEFINE_ACTION_FUNCTION(AActor, A_SinkGib) { + PARAM_ACTION_PROLOGUE; + self->floorclip += FRACUNIT; + return 0; } //============================================================================ @@ -245,7 +278,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_SinkGib) DEFINE_ACTION_FUNCTION(AActor, A_DelayGib) { + PARAM_ACTION_PROLOGUE; + self->tics -= pr_delaygib()>>2; + return 0; } //============================================================================ @@ -256,6 +292,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_DelayGib) DEFINE_ACTION_FUNCTION(AActor, A_SerpentHeadCheck) { + PARAM_ACTION_PROLOGUE; + if (self->z <= self->floorz) { if (Terrains[P_GetThingFloorType(self)].IsLiquid) @@ -268,5 +306,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentHeadCheck) self->SetState (self->FindState(NAME_Death)); } } + return 0; } diff --git a/src/g_hexen/a_spike.cpp b/src/g_hexen/a_spike.cpp index ea9d7c3d2..741781280 100644 --- a/src/g_hexen/a_spike.cpp +++ b/src/g_hexen/a_spike.cpp @@ -78,16 +78,21 @@ void AThrustFloor::Deactivate (AActor *activator) DEFINE_ACTION_FUNCTION(AActor, A_ThrustInitUp) { + PARAM_ACTION_PROLOGUE; + self->special2 = 5; // Raise speed self->args[0] = 1; // Mark as up self->floorclip = 0; self->flags = MF_SOLID; self->flags2 = MF2_NOTELEPORT|MF2_FLOORCLIP; self->special1 = 0L; + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_ThrustInitDn) { + PARAM_ACTION_PROLOGUE; + self->special2 = 5; // Raise speed self->args[0] = 0; // Mark as down self->floorclip = self->GetDefault()->height; @@ -96,11 +101,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_ThrustInitDn) self->renderflags = RF_INVISIBLE; static_cast<AThrustFloor *>(self)->DirtClump = Spawn("DirtClump", self->x, self->y, self->z, ALLOW_REPLACE); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_ThrustRaise) { + PARAM_ACTION_PROLOGUE; + AThrustFloor *actor = static_cast<AThrustFloor *>(self); if (A_RaiseMobj (actor, self->special2*FRACUNIT)) @@ -123,10 +131,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_ThrustRaise) if (pr_thrustraise()<40) P_SpawnDirt (actor, actor->radius); actor->special2++; // Increase raise speed + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_ThrustLower) { + PARAM_ACTION_PROLOGUE; + if (A_SinkMobj (self, 6*FRACUNIT)) { self->args[0] = 0; @@ -135,10 +146,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_ThrustLower) else self->SetStateNF (self->FindState ("ThrustInit1")); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_ThrustImpale) { + PARAM_ACTION_PROLOGUE; + AActor *thing; FBlockThingsIterator it(FBoundingBox(self->x, self->y, self->radius)); while ((thing = it.Next())) @@ -158,5 +172,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_ThrustImpale) P_TraceBleed (10001, thing); self->args[1] = 1; // Mark thrust thing as bloody } + return 0; } diff --git a/src/g_hexen/a_summon.cpp b/src/g_hexen/a_summon.cpp index 69c0238ba..6f698cbc2 100644 --- a/src/g_hexen/a_summon.cpp +++ b/src/g_hexen/a_summon.cpp @@ -49,6 +49,8 @@ bool AArtiDarkServant::Use (bool pickup) DEFINE_ACTION_FUNCTION(AActor, A_Summon) { + PARAM_ACTION_PROLOGUE; + AMinotaurFriend *mo; mo = Spawn<AMinotaurFriend> (self->x, self->y, self->z, ALLOW_REPLACE); @@ -59,7 +61,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Summon) mo->Destroy (); AActor *arti = Spawn<AArtiDarkServant> (self->x, self->y, self->z, ALLOW_REPLACE); if (arti) arti->flags |= MF_DROPPED; - return; + return 0; } mo->StartTime = level.maptime; @@ -82,4 +84,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_Summon) Spawn ("MinotaurSmoke", self->x, self->y, self->z, ALLOW_REPLACE); S_Sound (self, CHAN_VOICE, mo->ActiveSound, 1, ATTN_NORM); } + return 0; } diff --git a/src/g_hexen/a_teleportother.cpp b/src/g_hexen/a_teleportother.cpp index 22f0673f5..fd8fa9a48 100644 --- a/src/g_hexen/a_teleportother.cpp +++ b/src/g_hexen/a_teleportother.cpp @@ -65,30 +65,41 @@ static void TeloSpawn (AActor *source, const char *type) DEFINE_ACTION_FUNCTION(AActor, A_TeloSpawnA) { + PARAM_ACTION_PROLOGUE; TeloSpawn (self, "TelOtherFX2"); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_TeloSpawnB) { + PARAM_ACTION_PROLOGUE; TeloSpawn (self, "TelOtherFX3"); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_TeloSpawnC) { + PARAM_ACTION_PROLOGUE; TeloSpawn (self, "TelOtherFX4"); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_TeloSpawnD) { + PARAM_ACTION_PROLOGUE; TeloSpawn (self, "TelOtherFX5"); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_CheckTeleRing) { + PARAM_ACTION_PROLOGUE; + if (self->special1-- <= 0) { self->SetState (self->FindState(NAME_Death)); } + return 0; } //=========================================================================== diff --git a/src/g_hexen/a_wraith.cpp b/src/g_hexen/a_wraith.cpp index 219c3a6bb..9ed3fd3df 100644 --- a/src/g_hexen/a_wraith.cpp +++ b/src/g_hexen/a_wraith.cpp @@ -29,6 +29,8 @@ static FRandom pr_wraithfx4 ("WraithFX4"); DEFINE_ACTION_FUNCTION(AActor, A_WraithInit) { + PARAM_ACTION_PROLOGUE; + self->z += 48<<FRACBITS; // [RH] Make sure the wraith didn't go into the ceiling @@ -38,6 +40,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_WraithInit) } self->special1 = 0; // index into floatbob + return 0; } //============================================================================ @@ -48,11 +51,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_WraithInit) DEFINE_ACTION_FUNCTION(AActor, A_WraithRaiseInit) { + PARAM_ACTION_PROLOGUE; + self->renderflags &= ~RF_INVISIBLE; self->flags2 &= ~MF2_NONSHOOTABLE; self->flags3 &= ~MF3_DONTBLAST; self->flags |= MF_SHOOTABLE|MF_SOLID; self->floorclip = self->height; + return 0; } //============================================================================ @@ -63,6 +69,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_WraithRaiseInit) DEFINE_ACTION_FUNCTION(AActor, A_WraithRaise) { + PARAM_ACTION_PROLOGUE; + if (A_RaiseMobj (self, 2*FRACUNIT)) { // Reached it's target height @@ -75,6 +83,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_WraithRaise) } P_SpawnDirt (self, self->radius); + return 0; } //============================================================================ @@ -85,6 +94,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_WraithRaise) DEFINE_ACTION_FUNCTION(AActor, A_WraithMelee) { + PARAM_ACTION_PROLOGUE; + int amount; // Steal health from target and give to self @@ -94,6 +105,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_WraithMelee) P_DamageMobj (self->target, self, self, amount, NAME_Melee); self->health += amount; } + return 0; } //============================================================================ @@ -104,6 +116,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_WraithMelee) DEFINE_ACTION_FUNCTION(AActor, A_WraithFX2) { + PARAM_ACTION_PROLOGUE; + AActor *mo; angle_t angle; int i; @@ -130,6 +144,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_WraithFX2) mo->floorclip = 10*FRACUNIT; } } + return 0; } //============================================================================ @@ -142,6 +157,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_WraithFX2) DEFINE_ACTION_FUNCTION(AActor, A_WraithFX3) { + PARAM_ACTION_PROLOGUE; + AActor *mo; int numdropped = pr_wraithfx3()%15; @@ -156,6 +173,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_WraithFX3) mo->target = self; } } + return 0; } //============================================================================ @@ -225,6 +243,8 @@ void A_WraithFX4 (AActor *self) DEFINE_ACTION_FUNCTION(AActor, A_WraithChase) { + PARAM_ACTION_PROLOGUE; + int weaveindex = self->special1; self->z += FloatBobOffsets[weaveindex]; self->special1 = (weaveindex+2)&63; @@ -233,6 +253,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_WraithChase) // P_SetMobjState(self, S_WRAITH_RAISE2); // return; // } - A_Chase (self); + A_Chase (stack, self); A_WraithFX4 (self); + return 0; } diff --git a/src/g_raven/a_minotaur.cpp b/src/g_raven/a_minotaur.cpp index 3dc9e141a..1057a7c9b 100644 --- a/src/g_raven/a_minotaur.cpp +++ b/src/g_raven/a_minotaur.cpp @@ -174,18 +174,23 @@ bool AMinotaurFriend::OkayToSwitchTarget (AActor *other) DEFINE_ACTION_FUNCTION(AActor, A_MinotaurDeath) { + PARAM_ACTION_PROLOGUE; + if (Wads.CheckNumForName ("MNTRF1", ns_sprites) < 0 && Wads.CheckNumForName ("MNTRF0", ns_sprites) < 0) self->SetState(self->FindState ("FadeOut")); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk1) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (!self->target) { - return; + return 0; } S_Sound (self, CHAN_WEAPON, "minotaur/melee", 1, ATTN_NORM); if (self->CheckMeleeRange()) @@ -199,6 +204,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk1) player->deltaviewheight = -16*FRACUNIT; } } + return 0; } //---------------------------------------------------------------------------- @@ -213,6 +219,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk1) DEFINE_ACTION_FUNCTION(AActor, A_MinotaurDecide) { + PARAM_ACTION_PROLOGUE; + bool friendly = !!(self->flags5 & MF5_SUMMONEDMONSTER); angle_t angle; AActor *target; @@ -221,7 +229,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurDecide) target = self->target; if (!target) { - return; + return 0; } if (!friendly) { @@ -260,6 +268,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurDecide) // Don't need to call P_SetMobjState because the current state // falls through to the swing attack } + return 0; } //---------------------------------------------------------------------------- @@ -270,10 +279,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurDecide) DEFINE_ACTION_FUNCTION(AActor, A_MinotaurCharge) { + PARAM_ACTION_PROLOGUE; + AActor *puff; - if (!self->target) return; - + if (self->target == NULL) + { + return 0; + } if (self->special1 > 0) { const PClass *type; @@ -296,6 +309,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurCharge) self->flags2 &= ~MF2_INVULNERABLE; self->SetState (self->SeeState); } + return 0; } //---------------------------------------------------------------------------- @@ -308,15 +322,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurCharge) DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk2) { + PARAM_ACTION_PROLOGUE; + AActor *mo; angle_t angle; fixed_t velz; fixed_t z; bool friendly = !!(self->flags5 & MF5_SUMMONEDMONSTER); - if (!self->target) + if (self->target == NULL) { - return; + return 0; } S_Sound (self, CHAN_WEAPON, "minotaur/attack2", 1, ATTN_NORM); if (self->CheckMeleeRange()) @@ -325,7 +341,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk2) damage = pr_atk.HitDice (friendly ? 3 : 5); P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (damage, self->target, self); - return; + return 0; } z = self->z + 40*FRACUNIT; const PClass *fx = PClass::FindClass("MinotaurFX1"); @@ -343,6 +359,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk2) P_SpawnMissileAngleZ (self, z, fx, angle+(ANG45/16), velz); } } + return 0; } //---------------------------------------------------------------------------- @@ -355,13 +372,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk2) DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk3) { + PARAM_ACTION_PROLOGUE; + AActor *mo; player_t *player; bool friendly = !!(self->flags5 & MF5_SUMMONEDMONSTER); if (!self->target) { - return; + return 0; } S_Sound (self, CHAN_VOICE, "minotaur/attack3", 1, ATTN_NORM); if (self->CheckMeleeRange()) @@ -398,6 +417,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk3) self->SetState (self->FindState ("HammerLoop")); self->special2 = 1; } + return 0; } //---------------------------------------------------------------------------- @@ -408,6 +428,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk3) DEFINE_ACTION_FUNCTION(AActor, A_MntrFloorFire) { + PARAM_ACTION_PROLOGUE; + AActor *mo; fixed_t x, y; @@ -418,6 +440,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MntrFloorFire) mo->target = self->target; mo->velx = 1; // Force block checking P_CheckMissileSpawn (mo); + return 0; } //--------------------------------------------------------------------------- @@ -464,6 +487,8 @@ void P_MinotaurSlam (AActor *source, AActor *target) DEFINE_ACTION_FUNCTION(AActor, A_MinotaurRoam) { + PARAM_ACTION_PROLOGUE; + // In case pain caused him to skip his fade in. self->RenderStyle = STYLE_Normal; @@ -474,7 +499,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurRoam) if (self1->StartTime >= 0 && (level.maptime - self1->StartTime) >= MAULATORTICS) { P_DamageMobj (self1, NULL, NULL, TELEFRAG_DAMAGE, NAME_None); - return; + return 0; } } @@ -496,6 +521,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurRoam) self->movedir = (self->movedir+7)%8; FaceMovementDirection (self); } + return 0; } @@ -509,10 +535,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurRoam) DEFINE_ACTION_FUNCTION(AActor, A_MinotaurLook) { + PARAM_ACTION_PROLOGUE; + if (!self->IsKindOf(RUNTIME_CLASS(AMinotaurFriend))) { CALL_ACTION(A_Look, self); - return; + return 0; } AActor *mo = NULL; @@ -573,14 +601,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurLook) { self->SetStateNF (self->FindState ("Roam")); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_MinotaurChase) { + PARAM_ACTION_PROLOGUE; + if (!self->IsKindOf(RUNTIME_CLASS(AMinotaurFriend))) { - A_Chase (self); - return; + A_Chase (stack, self); + return 0; } AMinotaurFriend *self1 = static_cast<AMinotaurFriend *> (self); @@ -591,7 +622,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurChase) if (self1->StartTime >= 0 && (level.maptime - self1->StartTime) >= MAULATORTICS) { P_DamageMobj (self1, NULL, NULL, TELEFRAG_DAMAGE, NAME_None); - return; + return 0; } if (pr_minotaurchase() < 30) @@ -601,7 +632,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurChase) !(self1->target->flags&MF_SHOOTABLE)) { // look for a new target self1->SetState (self1->FindState ("Spawn")); - return; + return 0; } FaceMovementDirection (self1); @@ -615,14 +646,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurChase) S_Sound (self1, CHAN_WEAPON, self1->AttackSound, 1, ATTN_NORM); } self1->SetState (self1->MeleeState); - return; + return 0; } // Missile attack if (self1->MissileState && P_CheckMissileRange(self1)) { self1->SetState (self1->MissileState); - return; + return 0; } // chase towards target @@ -637,5 +668,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurChase) { self1->PlayActiveSound (); } + return 0; } diff --git a/src/g_shared/a_action.cpp b/src/g_shared/a_action.cpp index 767d282b8..494ea11f0 100644 --- a/src/g_shared/a_action.cpp +++ b/src/g_shared/a_action.cpp @@ -59,6 +59,8 @@ IMPLEMENT_CLASS (ASwitchingDecoration) DEFINE_ACTION_FUNCTION(AActor, A_NoBlocking) { + PARAM_ACTION_PROLOGUE; + // [RH] Andy Baker's stealth monsters if (self->flags & MF_STEALTH) { @@ -73,7 +75,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_NoBlocking) { P_DropItem (self, self->Conversation->DropType, -1, 256); self->Conversation = NULL; - return; + return 0; } self->Conversation = NULL; @@ -96,11 +98,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_NoBlocking) } } } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_Fall) { + PARAM_ACTION_PROLOGUE; + CALL_ACTION(A_NoBlocking, self); + return 0; } //========================================================================== @@ -111,8 +117,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_Fall) DEFINE_ACTION_FUNCTION(AActor, A_SetFloorClip) { + PARAM_ACTION_PROLOGUE; + self->flags2 |= MF2_FLOORCLIP; self->AdjustFloorClip (); + return 0; } //========================================================================== @@ -123,8 +132,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetFloorClip) DEFINE_ACTION_FUNCTION(AActor, A_UnSetFloorClip) { + PARAM_ACTION_PROLOGUE; + self->flags2 &= ~MF2_FLOORCLIP; self->floorclip = 0; + return 0; } //========================================================================== @@ -135,7 +147,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_UnSetFloorClip) DEFINE_ACTION_FUNCTION(AActor, A_HideThing) { + PARAM_ACTION_PROLOGUE; + self->renderflags |= RF_INVISIBLE; + return 0; } //========================================================================== @@ -146,7 +161,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_HideThing) DEFINE_ACTION_FUNCTION(AActor, A_UnHideThing) { + PARAM_ACTION_PROLOGUE; + self->renderflags &= ~RF_INVISIBLE; + return 0; } //============================================================================ @@ -157,6 +175,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_UnHideThing) DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeath) { + PARAM_ACTION_PROLOGUE; + int t = pr_freezedeath(); self->tics = 75+t+pr_freezedeath(); self->flags |= MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD|MF_ICECORPSE; @@ -184,6 +204,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeath) self->args[1], self->args[2], self->args[3], self->args[4]); self->special = 0; } + return 0; } //========================================================================== @@ -194,8 +215,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeath) DEFINE_ACTION_FUNCTION(AActor, A_GenericFreezeDeath) { + PARAM_ACTION_PROLOGUE; + self->Translation = TRANSLATION(TRANSLATION_Standard, 7); CALL_ACTION(A_FreezeDeath, self); + return 0; } //============================================================================ @@ -206,6 +230,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_GenericFreezeDeath) DEFINE_ACTION_FUNCTION(AActor, A_IceSetTics) { + PARAM_ACTION_PROLOGUE; + int floor; self->tics = 70+(pr_icesettics()&63); @@ -218,6 +244,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceSetTics) { self->tics <<= 1; } + return 0; } //============================================================================ @@ -228,6 +255,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceSetTics) DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeathChunks) { + PARAM_ACTION_PROLOGUE; int i; int numChunks; @@ -236,7 +264,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeathChunks) if (self->velx || self->vely || self->velz) { self->tics = 3*TICRATE; - return; + return 0; } S_Sound (self, CHAN_BODY, "misc/icebreak", 1, ATTN_NORM); @@ -297,6 +325,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeathChunks) CALL_ACTION(A_NoBlocking, self); self->SetState(self->FindState(NAME_Null)); + return 0; } //---------------------------------------------------------------------------- @@ -400,13 +429,20 @@ void DCorpsePointer::Serialize (FArchive &arc) // throw another corpse on the queue DEFINE_ACTION_FUNCTION(AActor, A_QueueCorpse) { + PARAM_ACTION_PROLOGUE; + if (sv_corpsequeuesize > 0) + { new DCorpsePointer (self); + } + return 0; } // Remove an self from the queue (for resurrection) DEFINE_ACTION_FUNCTION(AActor, A_DeQueueCorpse) { + PARAM_ACTION_PROLOGUE; + TThinkerIterator<DCorpsePointer> iterator (STAT_CORPSEPOINTER); DCorpsePointer *corpsePtr; @@ -416,9 +452,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeQueueCorpse) { corpsePtr->Corpse = NULL; corpsePtr->Destroy (); - return; + return 0; } } + return 0; } //============================================================================ @@ -429,7 +466,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeQueueCorpse) DEFINE_ACTION_FUNCTION(AActor, A_SetInvulnerable) { + PARAM_ACTION_PROLOGUE; + self->flags2 |= MF2_INVULNERABLE; + return 0; } //============================================================================ @@ -440,7 +480,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetInvulnerable) DEFINE_ACTION_FUNCTION(AActor, A_UnSetInvulnerable) { + PARAM_ACTION_PROLOGUE; + self->flags2 &= ~MF2_INVULNERABLE; + return 0; } //============================================================================ @@ -451,7 +494,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_UnSetInvulnerable) DEFINE_ACTION_FUNCTION(AActor, A_SetReflective) { + PARAM_ACTION_PROLOGUE; + self->flags2 |= MF2_REFLECTIVE; + return 0; } //============================================================================ @@ -462,7 +508,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetReflective) DEFINE_ACTION_FUNCTION(AActor, A_UnSetReflective) { + PARAM_ACTION_PROLOGUE; + self->flags2 &= ~MF2_REFLECTIVE; + return 0; } //============================================================================ @@ -473,7 +522,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_UnSetReflective) DEFINE_ACTION_FUNCTION(AActor, A_SetReflectiveInvulnerable) { + PARAM_ACTION_PROLOGUE; + self->flags2 |= MF2_REFLECTIVE|MF2_INVULNERABLE; + return 0; } //============================================================================ @@ -484,7 +536,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetReflectiveInvulnerable) DEFINE_ACTION_FUNCTION(AActor, A_UnSetReflectiveInvulnerable) { + PARAM_ACTION_PROLOGUE; + self->flags2 &= ~(MF2_REFLECTIVE|MF2_INVULNERABLE); + return 0; } //========================================================================== @@ -495,8 +550,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_UnSetReflectiveInvulnerable) DEFINE_ACTION_FUNCTION(AActor, A_SetShootable) { + PARAM_ACTION_PROLOGUE; + self->flags2 &= ~MF2_NONSHOOTABLE; self->flags |= MF_SHOOTABLE; + return 0; } //========================================================================== @@ -507,8 +565,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetShootable) DEFINE_ACTION_FUNCTION(AActor, A_UnSetShootable) { + PARAM_ACTION_PROLOGUE; + self->flags2 |= MF2_NONSHOOTABLE; self->flags &= ~MF_SHOOTABLE; + return 0; } //=========================================================================== @@ -519,7 +580,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_UnSetShootable) DEFINE_ACTION_FUNCTION(AActor, A_NoGravity) { + PARAM_ACTION_PROLOGUE; + self->flags |= MF_NOGRAVITY; + return 0; } //=========================================================================== @@ -530,8 +594,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_NoGravity) DEFINE_ACTION_FUNCTION(AActor, A_Gravity) { + PARAM_ACTION_PROLOGUE; + self->flags &= ~MF_NOGRAVITY; self->gravity = FRACUNIT; + return 0; } //=========================================================================== @@ -542,8 +609,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_Gravity) DEFINE_ACTION_FUNCTION(AActor, A_LowGravity) { + PARAM_ACTION_PROLOGUE; + self->flags &= ~MF_NOGRAVITY; self->gravity = FRACUNIT/8; + return 0; } //=========================================================================== diff --git a/src/g_shared/a_bridge.cpp b/src/g_shared/a_bridge.cpp index 7e743a0af..99a7c1a70 100644 --- a/src/g_shared/a_bridge.cpp +++ b/src/g_shared/a_bridge.cpp @@ -72,10 +72,12 @@ void ACustomBridge::BeginPlay () DEFINE_ACTION_FUNCTION(AActor, A_BridgeOrbit) { + PARAM_ACTION_PROLOGUE; + if (self->target == NULL) { // Don't crash if somebody spawned this into the world // independantly of a Bridge actor. - return; + return 0; } // Set default values // Every five tics, Hexen moved the ball 3/256th of a revolution. @@ -97,18 +99,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_BridgeOrbit) self->x = self->target->x + rotationradius * finecosine[self->angle >> ANGLETOFINESHIFT]; self->y = self->target->y + rotationradius * finesine[self->angle >> ANGLETOFINESHIFT]; self->z = self->target->z; + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BridgeInit) { + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT(balltype, AActor) { balltype = NULL; } + angle_t startangle; AActor *ball; fixed_t cx, cy, cz; - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(balltype, 0); - if (balltype == NULL) balltype = PClass::FindClass("BridgeBall"); cx = self->x; @@ -127,6 +130,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BridgeInit) ball->target = self; CALL_ACTION(A_BridgeOrbit, ball); } + return 0; } /* never used diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index e9d9e2003..ad5505be2 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -266,11 +266,14 @@ bool P_GiveBody (AActor *actor, int num) DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialThing1) { + PARAM_ACTION_PROLOGUE; + self->renderflags &= ~RF_INVISIBLE; if (static_cast<AInventory *>(self)->DoRespawn ()) { S_Sound (self, CHAN_VOICE, "misc/spawn", 1, ATTN_IDLE); } + return 0; } //--------------------------------------------------------------------------- @@ -281,12 +284,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialThing1) DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialThing2) { + PARAM_ACTION_PROLOGUE; + self->flags |= MF_SPECIAL; if (!(self->GetDefault()->flags & MF_NOGRAVITY)) { self->flags &= ~MF_NOGRAVITY; } self->SetState (self->SpawnState); + return 0; } @@ -298,6 +304,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialThing2) DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialDoomThing) { + PARAM_ACTION_PROLOGUE; + self->renderflags &= ~RF_INVISIBLE; self->flags |= MF_SPECIAL; if (!(self->GetDefault()->flags & MF_NOGRAVITY)) @@ -310,6 +318,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialDoomThing) S_Sound (self, CHAN_VOICE, "misc/spawn", 1, ATTN_IDLE); Spawn ("ItemFog", self->x, self->y, self->z, ALLOW_REPLACE); } + return 0; } //--------------------------------------------------------------------------- @@ -320,6 +329,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialDoomThing) DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialPosition) { + PARAM_ACTION_PROLOGUE; + // Move item back to its original location fixed_t _x, _y; sector_t *sec; @@ -356,6 +367,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialPosition) self->z += FloatBobOffsets[(self->FloatBobPhase + level.maptime) & 63]; } } + return 0; } int AInventory::StaticLastMessageTic; diff --git a/src/g_shared/a_randomspawner.cpp b/src/g_shared/a_randomspawner.cpp index a5ffa9251..1d8ceaa54 100644 --- a/src/g_shared/a_randomspawner.cpp +++ b/src/g_shared/a_randomspawner.cpp @@ -164,7 +164,7 @@ class ARandomSpawner : public AActor Super::Tick(); if (tracer == NULL || tracer->health <= 0) { - CALL_ACTION(A_BossDeath, this); + A_BossDeath(this); Destroy(); } } @@ -172,4 +172,3 @@ class ARandomSpawner : public AActor }; IMPLEMENT_CLASS (ARandomSpawner) - diff --git a/src/g_shared/a_specialspot.cpp b/src/g_shared/a_specialspot.cpp index dbf2cffca..8bf280e78 100644 --- a/src/g_shared/a_specialspot.cpp +++ b/src/g_shared/a_specialspot.cpp @@ -384,36 +384,36 @@ void ASpecialSpot::Destroy() DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnSingleItem) { + PARAM_ACTION_PROLOGUE; + PARAM_CLASS (cls, AActor); + PARAM_INT_OPT (fail_sp) { fail_sp = 0; } + PARAM_INT_OPT (fail_co) { fail_co = 0; } + PARAM_INT_OPT (fail_dm) { fail_dm = 0; } + AActor *spot = NULL; DSpotState *state = DSpotState::GetSpotState(); if (state != NULL) spot = state->GetRandomSpot(RUNTIME_TYPE(self), true); - if (spot == NULL) return; - - ACTION_PARAM_START(4); - ACTION_PARAM_CLASS(cls, 0); - ACTION_PARAM_INT(fail_sp, 1); - ACTION_PARAM_INT(fail_co, 2); - ACTION_PARAM_INT(fail_dm, 3); + if (spot == NULL) return 0; if (!multiplayer && pr_spawnmace() < fail_sp) { // Sometimes doesn't show up if not in deathmatch - return; + return 0; } if (multiplayer && !deathmatch && pr_spawnmace() < fail_co) { - return; + return 0; } if (deathmatch && pr_spawnmace() < fail_dm) { - return; + return 0; } if (cls == NULL) { - return; + return 0; } AActor *spawned = Spawn(cls, self->x, self->y, self->z, ALLOW_REPLACE); @@ -432,5 +432,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnSingleItem) static_cast<AInventory*>(spawned)->SpawnPointClass = RUNTIME_TYPE(self); } } + return 0; } diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index e02391640..d2387fba0 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -1702,23 +1702,24 @@ const PClass *Net_ReadWeapon(BYTE **stream) DEFINE_ACTION_FUNCTION_PARAMS(AWeapon, A_ZoomFactor) { - ACTION_PARAM_START(2); - ACTION_PARAM_FLOAT(zoom, 0); - ACTION_PARAM_INT(flags, 1); + PARAM_ACTION_PROLOGUE; + PARAM_FLOAT_OPT (zoom) { zoom = 1; } + PARAM_INT_OPT (flags) { flags = 0; } if (self->player != NULL && self->player->ReadyWeapon != NULL) { - zoom = 1 / clamp(zoom, 0.1f, 50.f); + zoom = 1 / clamp(zoom, 0.1, 50.0); if (flags & 1) { // Make the zoom instant. - self->player->FOV = self->player->DesiredFOV * zoom; + self->player->FOV = float(self->player->DesiredFOV * zoom); } if (flags & 2) { // Disable pitch/yaw scaling. zoom = -zoom; } - self->player->ReadyWeapon->FOVScale = zoom; + self->player->ReadyWeapon->FOVScale = float(zoom); } + return 0; } //=========================================================================== @@ -1729,11 +1730,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AWeapon, A_ZoomFactor) DEFINE_ACTION_FUNCTION_PARAMS(AWeapon, A_SetCrosshair) { - ACTION_PARAM_START(1); - ACTION_PARAM_INT(xhair, 0); + PARAM_ACTION_PROLOGUE; + PARAM_INT(xhair); if (self->player != NULL && self->player->ReadyWeapon != NULL) { self->player->ReadyWeapon->Crosshair = xhair; } + return 0; } diff --git a/src/g_strife/a_acolyte.cpp b/src/g_strife/a_acolyte.cpp index 6785de1ac..9b84b92bb 100644 --- a/src/g_strife/a_acolyte.cpp +++ b/src/g_strife/a_acolyte.cpp @@ -27,11 +27,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_HideDecepticon) { + PARAM_ACTION_PROLOGUE; + EV_DoDoor (DDoor::doorClose, NULL, self, 999, 8*FRACUNIT, 0, 0, 0); if (self->target != NULL && self->target->player != NULL) { P_NoiseAlert (self->target, self); } + return 0; } //============================================================================ @@ -42,6 +45,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_HideDecepticon) DEFINE_ACTION_FUNCTION(AActor, A_AcolyteDie) { + PARAM_ACTION_PROLOGUE; + int i; // [RH] Disable translucency here. @@ -49,7 +54,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_AcolyteDie) // Only the Blue Acolyte does extra stuff on death. if (self->GetClass()->TypeName != NAME_AcolyteBlue) - return; + return 0; // Make sure somebody is still alive for (i = 0; i < MAXPLAYERS; ++i) @@ -58,7 +63,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_AcolyteDie) break; } if (i == MAXPLAYERS) - return; + return 0; // Make sure all the other blue acolytes are dead. TThinkerIterator<AActor> iterator(NAME_AcolyteBlue); @@ -68,7 +73,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_AcolyteDie) { if (other != self && other->health > 0) { // Found a living one - return; + return 0; } } @@ -76,6 +81,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_AcolyteDie) players[i].SetLogNumber (14); S_StopSound (CHAN_VOICE); S_Sound (CHAN_VOICE, "svox/voc14", 1, ATTN_NORM); + return 0; } //============================================================================ @@ -86,9 +92,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_AcolyteDie) DEFINE_ACTION_FUNCTION(AActor, A_BeShadowyFoe) { + PARAM_ACTION_PROLOGUE; + self->RenderStyle = STYLE_Translucent; self->alpha = HR_SHADOW; self->flags &= ~MF_FRIENDLY; + return 0; } //============================================================================ @@ -99,6 +108,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeShadowyFoe) DEFINE_ACTION_FUNCTION(AActor, A_AcolyteBits) { + PARAM_ACTION_PROLOGUE; + if (self->SpawnFlags & MTF_SHADOW) { CALL_ACTION(A_BeShadowyFoe, self); @@ -115,4 +126,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_AcolyteBits) self->RenderStyle.BlendOp = STYLEOP_None; } } + return 0; } diff --git a/src/g_strife/a_alienspectres.cpp b/src/g_strife/a_alienspectres.cpp index 6506cdb1c..1c58805b9 100644 --- a/src/g_strife/a_alienspectres.cpp +++ b/src/g_strife/a_alienspectres.cpp @@ -22,6 +22,8 @@ AActor *P_SpawnSubMissile (AActor *source, const PClass *type, AActor *target); DEFINE_ACTION_FUNCTION(AActor, A_SpectreChunkSmall) { + PARAM_ACTION_PROLOGUE; + AActor *foo = Spawn("AlienChunkSmall", self->x, self->y, self->z + 10*FRACUNIT, ALLOW_REPLACE); if (foo != NULL) @@ -36,10 +38,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpectreChunkSmall) foo->velz = (pr_spectrechunk() & 15) << FRACBITS; } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_SpectreChunkLarge) { + PARAM_ACTION_PROLOGUE; + AActor *foo = Spawn("AlienChunkLarge", self->x, self->y, self->z + 10*FRACUNIT, ALLOW_REPLACE); if (foo != NULL) @@ -54,13 +59,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpectreChunkLarge) foo->velz = (pr_spectrechunk() & 7) << FRACBITS; } - + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_Spectre3Attack) { + PARAM_ACTION_PROLOGUE; + if (self->target == NULL) - return; + return 0; AActor *foo = Spawn("SpectralLightningV2", self->x, self->y, self->z + 32*FRACUNIT, ALLOW_REPLACE); @@ -76,10 +83,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_Spectre3Attack) P_SpawnSubMissile (self, PClass::FindClass("SpectralLightningBall2"), self); } self->angle -= ANGLE_180 / 20 * 10; + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_AlienSpectreDeath) { + PARAM_ACTION_PROLOGUE; + AActor *player; char voc[32]; int log; @@ -88,7 +98,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_AlienSpectreDeath) CALL_ACTION(A_NoBlocking, self); // [RH] Need this for Sigil rewarding if (!CheckBossDeath (self)) { - return; + return 0; } for (i = 0, player = NULL; i < MAXPLAYERS; ++i) { @@ -100,7 +110,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_AlienSpectreDeath) } if (player == NULL) { - return; + return 0; } switch (self->GetClass()->TypeName) @@ -184,9 +194,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_AlienSpectreDeath) break; default: - return; + return 0; } mysnprintf (voc, countof(voc), "svox/voc%d", log); S_Sound (CHAN_VOICE, voc, 1, ATTN_NORM); player->player->SetLogNumber (log); + return 0; } diff --git a/src/g_strife/a_crusader.cpp b/src/g_strife/a_crusader.cpp index f4f0024fd..1b32c8051 100644 --- a/src/g_strife/a_crusader.cpp +++ b/src/g_strife/a_crusader.cpp @@ -20,8 +20,10 @@ bool Sys_1ed64 (AActor *self) DEFINE_ACTION_FUNCTION(AActor, A_CrusaderChoose) { + PARAM_ACTION_PROLOGUE; + if (self->target == NULL) - return; + return 0; if (Sys_1ed64 (self)) { @@ -44,42 +46,55 @@ DEFINE_ACTION_FUNCTION(AActor, A_CrusaderChoose) } self->SetState (self->SeeState); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_CrusaderSweepLeft) { + PARAM_ACTION_PROLOGUE; + self->angle += ANGLE_90/16; AActor *misl = P_SpawnMissileZAimed (self, self->z + 48*FRACUNIT, self->target, PClass::FindClass("FastFlameMissile")); if (misl != NULL) { misl->velz += FRACUNIT; } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_CrusaderSweepRight) { + PARAM_ACTION_PROLOGUE; + self->angle -= ANGLE_90/16; AActor *misl = P_SpawnMissileZAimed (self, self->z + 48*FRACUNIT, self->target, PClass::FindClass("FastFlameMissile")); if (misl != NULL) { misl->velz += FRACUNIT; } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_CrusaderRefire) { + PARAM_ACTION_PROLOGUE; + if (self->target == NULL || self->target->health <= 0 || !P_CheckSight (self, self->target)) { self->SetState (self->SeeState); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_CrusaderDeath) { + PARAM_ACTION_PROLOGUE; + if (CheckBossDeath (self)) { EV_DoFloor (DFloor::floorLowerToLowest, NULL, 667, FRACUNIT, 0, 0, 0, false); } + return 0; } diff --git a/src/g_strife/a_entityboss.cpp b/src/g_strife/a_entityboss.cpp index f69d43fc6..3df9a786a 100644 --- a/src/g_strife/a_entityboss.cpp +++ b/src/g_strife/a_entityboss.cpp @@ -14,10 +14,13 @@ static FRandom pr_entity ("Entity"); DEFINE_ACTION_FUNCTION(AActor, A_SubEntityDeath) { + PARAM_ACTION_PROLOGUE; + if (CheckBossDeath (self)) { G_ExitLevel (0, false); } + return 0; } void A_SpectralMissile (AActor *self, const char *missilename) @@ -41,6 +44,8 @@ DECLARE_ACTION(A_Spectre3Attack) DEFINE_ACTION_FUNCTION(AActor, A_EntityAttack) { + PARAM_ACTION_PROLOGUE; + // Apparent Strife bug: Case 5 was unreachable because they used % 5 instead of % 6. // I've fixed that by making case 1 duplicate it, since case 1 did nothing. switch (pr_entity() % 5) @@ -66,11 +71,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_EntityAttack) A_SpectralMissile (self, "SpectralLightningBigBall2"); break; } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_SpawnEntity) { + PARAM_ACTION_PROLOGUE; + AActor *entity = Spawn("EntityBoss", self->x, self->y, self->z + 70*FRACUNIT, ALLOW_REPLACE); if (entity != NULL) { @@ -79,10 +87,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnEntity) entity->velz = 5*FRACUNIT; entity->tracer = self; } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_EntityDeath) { + PARAM_ACTION_PROLOGUE; + AActor *second; fixed_t secondRadius = GetDefaultByName("EntitySecond")->radius * 2; angle_t an; @@ -121,4 +132,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_EntityDeath) second->velx = FixedMul (secondRadius, finecosine[an]) << 2; second->vely = FixedMul (secondRadius, finesine[an]) << 2; A_FaceTarget (second); + return 0; } diff --git a/src/g_strife/a_inquisitor.cpp b/src/g_strife/a_inquisitor.cpp index 14bfdf57f..3835a314f 100644 --- a/src/g_strife/a_inquisitor.cpp +++ b/src/g_strife/a_inquisitor.cpp @@ -12,8 +12,11 @@ static FRandom pr_inq ("Inquisitor"); DEFINE_ACTION_FUNCTION(AActor, A_InquisitorWalk) { + PARAM_ACTION_PROLOGUE; + S_Sound (self, CHAN_BODY, "inquisitor/walk", 1, ATTN_NORM); - A_Chase (self); + A_Chase (stack, self); + return 0; } bool InquisitorCheckDistance (AActor *self) @@ -27,8 +30,10 @@ bool InquisitorCheckDistance (AActor *self) DEFINE_ACTION_FUNCTION(AActor, A_InquisitorDecide) { + PARAM_ACTION_PROLOGUE; + if (self->target == NULL) - return; + return 0; A_FaceTarget (self); if (!InquisitorCheckDistance (self)) @@ -42,14 +47,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_InquisitorDecide) self->SetState (self->FindState("Jump")); } } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_InquisitorAttack) { + PARAM_ACTION_PROLOGUE; + AActor *proj; if (self->target == NULL) - return; + return 0; A_FaceTarget (self); @@ -67,16 +75,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_InquisitorAttack) proj->velz += 16*FRACUNIT; } self->z -= 32*FRACBITS; + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_InquisitorJump) { + PARAM_ACTION_PROLOGUE; + fixed_t dist; fixed_t speed; angle_t an; if (self->target == NULL) - return; + return 0; S_Sound (self, CHAN_ITEM|CHAN_LOOP, "inquisitor/jump", 1, ATTN_NORM); self->z += 64*FRACUNIT; @@ -94,10 +105,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_InquisitorJump) self->velz = (self->target->z - self->z) / dist; self->reactiontime = 60; self->flags |= MF_NOGRAVITY; + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_InquisitorCheckLand) { + PARAM_ACTION_PROLOGUE; + self->reactiontime--; if (self->reactiontime < 0 || self->velx == 0 || @@ -108,21 +122,24 @@ DEFINE_ACTION_FUNCTION(AActor, A_InquisitorCheckLand) self->reactiontime = 0; self->flags &= ~MF_NOGRAVITY; S_StopSound (self, CHAN_ITEM); - return; + return 0; } if (!S_IsActorPlayingSomething (self, CHAN_ITEM, -1)) { S_Sound (self, CHAN_ITEM|CHAN_LOOP, "inquisitor/jump", 1, ATTN_NORM); } - + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_TossArm) { + PARAM_ACTION_PROLOGUE; + AActor *foo = Spawn("InquisitorArm", self->x, self->y, self->z + 24*FRACUNIT, ALLOW_REPLACE); foo->angle = self->angle - ANGLE_90 + (pr_inq.Random2() << 22); foo->velx = FixedMul (foo->Speed, finecosine[foo->angle >> ANGLETOFINESHIFT]) >> 3; foo->vely = FixedMul (foo->Speed, finesine[foo->angle >> ANGLETOFINESHIFT]) >> 3; foo->velz = pr_inq() << 10; + return 0; } diff --git a/src/g_strife/a_loremaster.cpp b/src/g_strife/a_loremaster.cpp index 8613aacee..b22a935ab 100644 --- a/src/g_strife/a_loremaster.cpp +++ b/src/g_strife/a_loremaster.cpp @@ -41,8 +41,11 @@ int ALoreShot::DoSpecialDamage (AActor *target, int damage) DEFINE_ACTION_FUNCTION(AActor, A_LoremasterChain) { + PARAM_ACTION_PROLOGUE; + S_Sound (self, CHAN_BODY, "loremaster/active", 1, ATTN_NORM); Spawn("LoreShot2", self->x, self->y, self->z, ALLOW_REPLACE); Spawn("LoreShot2", self->x - (self->velx >> 1), self->y - (self->vely >> 1), self->z - (self->velz >> 1), ALLOW_REPLACE); Spawn("LoreShot2", self->x - self->velx, self->y - self->vely, self->z - self->velz, ALLOW_REPLACE); + return 0; } diff --git a/src/g_strife/a_oracle.cpp b/src/g_strife/a_oracle.cpp index 11a9a52e4..519b68c10 100644 --- a/src/g_strife/a_oracle.cpp +++ b/src/g_strife/a_oracle.cpp @@ -20,6 +20,8 @@ IMPLEMENT_CLASS (AOracle) DEFINE_ACTION_FUNCTION(AActor, A_WakeOracleSpectre) { + PARAM_ACTION_PROLOGUE; + TThinkerIterator<AActor> it(NAME_AlienSpectre3); AActor *spectre = it.Next(); @@ -29,6 +31,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_WakeOracleSpectre) spectre->target = self->target; spectre->SetState (spectre->SeeState); } + return 0; } diff --git a/src/g_strife/a_programmer.cpp b/src/g_strife/a_programmer.cpp index 196fae584..7458476d4 100644 --- a/src/g_strife/a_programmer.cpp +++ b/src/g_strife/a_programmer.cpp @@ -75,21 +75,24 @@ PalEntry AProgLevelEnder::GetBlend () DEFINE_ACTION_FUNCTION(AActor, A_ProgrammerMelee) { + PARAM_ACTION_PROLOGUE; + int damage; if (self->target == NULL) - return; + return 0; A_FaceTarget (self); if (!self->CheckMeleeRange ()) - return; + return 0; S_Sound (self, CHAN_WEAPON, "programmer/clank", 1, ATTN_NORM); damage = ((pr_prog() % 10) + 1) * 6; P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (damage, self->target, self); + return 0; } //============================================================================ @@ -100,10 +103,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_ProgrammerMelee) DEFINE_ACTION_FUNCTION(AActor, A_SpotLightning) { + PARAM_ACTION_PROLOGUE; + AActor *spot; if (self->target == NULL) - return; + return 0; spot = Spawn("SpectralLightningSpot", self->target->x, self->target->y, self->target->floorz, ALLOW_REPLACE); if (spot != NULL) @@ -113,6 +118,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpotLightning) spot->health = -2; spot->tracer = self->target; } + return 0; } //============================================================================ @@ -123,6 +129,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpotLightning) DEFINE_ACTION_FUNCTION(AActor, A_SpawnProgrammerBase) { + PARAM_ACTION_PROLOGUE; + AActor *foo = Spawn("ProgrammerBase", self->x, self->y, self->z + 24*FRACUNIT, ALLOW_REPLACE); if (foo != NULL) { @@ -131,6 +139,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnProgrammerBase) foo->vely = FixedMul (foo->Speed, finesine[foo->angle >> ANGLETOFINESHIFT]); foo->velz = pr_prog() << 9; } + return 0; } //============================================================================ @@ -141,8 +150,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnProgrammerBase) DEFINE_ACTION_FUNCTION(AActor, A_ProgrammerDeath) { + PARAM_ACTION_PROLOGUE; + if (!CheckBossDeath (self)) - return; + return 0; for (int i = 0; i < MAXPLAYERS; ++i) { @@ -154,4 +165,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_ProgrammerDeath) } // the sky change scripts are now done as special actions in MAPINFO CALL_ACTION(A_BossDeath, self); + return 0; } diff --git a/src/g_strife/a_reaver.cpp b/src/g_strife/a_reaver.cpp index 893386534..33e933e23 100644 --- a/src/g_strife/a_reaver.cpp +++ b/src/g_strife/a_reaver.cpp @@ -13,6 +13,8 @@ static FRandom pr_reaverattack ("ReaverAttack"); DEFINE_ACTION_FUNCTION(AActor, A_ReaverRanged) { + PARAM_ACTION_PROLOGUE; + if (self->target != NULL) { angle_t bangle; @@ -30,4 +32,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_ReaverRanged) P_LineAttack (self, angle, MISSILERANGE, pitch, damage, NAME_None, NAME_StrifePuff); } } + return 0; } diff --git a/src/g_strife/a_rebels.cpp b/src/g_strife/a_rebels.cpp index 855da34fb..3944dd960 100644 --- a/src/g_strife/a_rebels.cpp +++ b/src/g_strife/a_rebels.cpp @@ -22,10 +22,12 @@ static FRandom pr_shootgun ("ShootGun"); DEFINE_ACTION_FUNCTION(AActor, A_ShootGun) { + PARAM_ACTION_PROLOGUE; + int pitch; if (self->target == NULL) - return; + return 0; S_Sound (self, CHAN_WEAPON, "monsters/rifle", 1, ATTN_NORM); A_FaceTarget (self); @@ -33,6 +35,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ShootGun) P_LineAttack (self, self->angle + (pr_shootgun.Random2() << 19), MISSILERANGE, pitch, 3*(pr_shootgun() % 5 + 1), NAME_None, NAME_StrifePuff); + return 0; } // Teleporter Beacon -------------------------------------------------------- @@ -71,6 +74,8 @@ bool ATeleporterBeacon::Use (bool pickup) DEFINE_ACTION_FUNCTION(AActor, A_Beacon) { + PARAM_ACTION_PROLOGUE; + AActor *owner = self->target; AActor *rebel; angle_t an; @@ -79,7 +84,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Beacon) if (!P_TryMove (rebel, rebel->x, rebel->y, true)) { rebel->Destroy (); - return; + return 0; } // Once the rebels start teleporting in, you can't pick up the beacon anymore. self->flags &= ~MF_SPECIAL; @@ -114,4 +119,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_Beacon) { self->SetState(self->FindState(NAME_Death)); } + return 0; } diff --git a/src/g_strife/a_sentinel.cpp b/src/g_strife/a_sentinel.cpp index 5f012cfb1..993cd1283 100644 --- a/src/g_strife/a_sentinel.cpp +++ b/src/g_strife/a_sentinel.cpp @@ -11,15 +11,17 @@ static FRandom pr_sentinelrefire ("SentinelRefire"); DEFINE_ACTION_FUNCTION(AActor, A_SentinelBob) { + PARAM_ACTION_PROLOGUE; + fixed_t minz, maxz; if (self->flags & MF_INFLOAT) { self->velz = 0; - return; + return 0; } if (self->threshold != 0) - return; + return 0; maxz = self->ceilingz - self->height - 16*FRACUNIT; minz = self->floorz + 96*FRACUNIT; @@ -36,16 +38,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_SentinelBob) self->velz += FRACUNIT; } self->reactiontime = (minz >= self->z) ? 4 : 0; + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_SentinelAttack) { + PARAM_ACTION_PROLOGUE; + AActor *missile, *trail; // [BB] Without a target the P_SpawnMissileZAimed call will crash. if (!self->target) { - return; + return 0; } missile = P_SpawnMissileZAimed (self, self->z + 32*FRACUNIT, self->target, PClass::FindClass("SentinelFX2")); @@ -69,10 +74,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_SentinelAttack) } missile->z += missile->velz >> 2; } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_SentinelRefire) { + PARAM_ACTION_PROLOGUE; + A_FaceTarget (self); if (pr_sentinelrefire() >= 30) @@ -86,4 +94,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_SentinelRefire) self->SetState (self->SeeState); } } + return 0; } diff --git a/src/g_strife/a_spectral.cpp b/src/g_strife/a_spectral.cpp index 9506b3412..4ab555660 100644 --- a/src/g_strife/a_spectral.cpp +++ b/src/g_strife/a_spectral.cpp @@ -28,14 +28,19 @@ void ASpectralMonster::Touch (AActor *toucher) DEFINE_ACTION_FUNCTION(AActor, A_SpectralLightningTail) { + PARAM_ACTION_PROLOGUE; + AActor *foo = Spawn("SpectralLightningHTail", self->x - self->velx, self->y - self->vely, self->z, ALLOW_REPLACE); foo->angle = self->angle; foo->health = self->health; + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_SpectralBigBallLightning) { + PARAM_ACTION_PROLOGUE; + const PClass *cls = PClass::FindClass("SpectralLightningH3"); if (cls) { @@ -46,12 +51,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpectralBigBallLightning) self->angle += ANGLE_90; P_SpawnSubMissile (self, cls, self->target); } + return 0; } static FRandom pr_zap5 ("Zap5"); DEFINE_ACTION_FUNCTION(AActor, A_SpectralLightning) { + PARAM_ACTION_PROLOGUE; + AActor *flash; fixed_t x, y; @@ -76,6 +84,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpectralLightning) flash->target = self->target; flash->velz = -18*FRACUNIT; flash->health = self->health; + return 0; } // In Strife, this number is stored in the data segment, but it doesn't seem to be @@ -84,6 +93,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpectralLightning) DEFINE_ACTION_FUNCTION(AActor, A_Tracer2) { + PARAM_ACTION_PROLOGUE; + AActor *dest; angle_t exact; fixed_t dist; @@ -92,7 +103,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer2) dest = self->tracer; if (!dest || dest->health <= 0 || self->Speed == 0 || !self->CanSeek(dest)) - return; + return 0; // change angle exact = R_PointToAngle2 (self->x, self->y, dest->x, dest->y); @@ -144,4 +155,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer2) self->velz += FRACUNIT/8; } } + return 0; } diff --git a/src/g_strife/a_stalker.cpp b/src/g_strife/a_stalker.cpp index 67cbd3282..2f0d5c4d3 100644 --- a/src/g_strife/a_stalker.cpp +++ b/src/g_strife/a_stalker.cpp @@ -13,6 +13,8 @@ static FRandom pr_stalker ("Stalker"); DEFINE_ACTION_FUNCTION(AActor, A_StalkerChaseDecide) { + PARAM_ACTION_PROLOGUE; + if (!(self->flags & MF_NOGRAVITY)) { self->SetState (self->FindState("SeeFloor")); @@ -21,10 +23,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_StalkerChaseDecide) { self->SetState (self->FindState("Drop")); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_StalkerLookInit) { + PARAM_ACTION_PROLOGUE; + FState *state; if (self->flags & MF_NOGRAVITY) { @@ -38,16 +43,22 @@ DEFINE_ACTION_FUNCTION(AActor, A_StalkerLookInit) { self->SetState (state); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_StalkerDrop) { + PARAM_ACTION_PROLOGUE; + self->flags5 &= ~MF5_NOVERTICALMELEERANGE; self->flags &= ~MF_NOGRAVITY; + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_StalkerAttack) { + PARAM_ACTION_PROLOGUE; + if (self->flags & MF_NOGRAVITY) { self->SetState (self->FindState("Drop")); @@ -63,11 +74,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_StalkerAttack) P_TraceBleed (damage, self->target, self); } } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_StalkerWalk) { + PARAM_ACTION_PROLOGUE; + S_Sound (self, CHAN_BODY, "stalker/walk", 1, ATTN_NORM); - A_Chase (self); + A_Chase (stack, self); + return 0; } diff --git a/src/g_strife/a_strifeitems.cpp b/src/g_strife/a_strifeitems.cpp index 06674a1ae..cd65b59ee 100644 --- a/src/g_strife/a_strifeitems.cpp +++ b/src/g_strife/a_strifeitems.cpp @@ -23,6 +23,8 @@ IMPLEMENT_CLASS(ADegninOre) DEFINE_ACTION_FUNCTION(AActor, A_RemoveForceField) { + PARAM_ACTION_PROLOGUE; + self->flags &= ~MF_SPECIAL; for (int i = 0; i < self->Sector->linecount; ++i) @@ -36,6 +38,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RemoveForceField) line->sidedef[1]->SetTexture(side_t::mid, FNullTextureID()); } } + return 0; } bool ADegninOre::Use (bool pickup) diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index 2764a2c0b..2865725ce 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -431,22 +431,30 @@ int AForceFieldGuard::TakeSpecialDamage (AActor *inflictor, AActor *source, int DEFINE_ACTION_FUNCTION(AActor, A_SetShadow) { + PARAM_ACTION_PROLOGUE; + self->flags |= MF_STRIFEx8000000|MF_SHADOW; self->RenderStyle = STYLE_Translucent; self->alpha = HR_SHADOW; + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_ClearShadow) { + PARAM_ACTION_PROLOGUE; + self->flags &= ~(MF_STRIFEx8000000|MF_SHADOW); self->RenderStyle = STYLE_Normal; self->alpha = OPAQUE; + return 0; } static FRandom pr_gethurt ("HurtMe!"); DEFINE_ACTION_FUNCTION(AActor, A_GetHurt) { + PARAM_ACTION_PROLOGUE; + self->flags4 |= MF4_INCOMBAT; if ((pr_gethurt() % 5) == 0) { @@ -457,16 +465,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_GetHurt) { self->Die (self->target, self->target); } + return 0; } // Klaxon Warning Light ----------------------------------------------------- DEFINE_ACTION_FUNCTION(AActor, A_TurretLook) { + PARAM_ACTION_PROLOGUE; + AActor *target; if (self->flags5 & MF5_INCONVERSATION) - return; + return 0; self->threshold = 0; target = self->LastHeard; @@ -478,7 +489,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_TurretLook) self->target = target; if ((self->flags & MF_AMBUSH) && !P_CheckSight (self, target)) { - return; + return 0; } if (self->SeeSound != 0) { @@ -488,10 +499,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_TurretLook) self->threshold = 10; self->SetState (self->SeeState); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_KlaxonBlare) { + PARAM_ACTION_PROLOGUE; + if (--self->reactiontime < 0) { self->target = NULL; @@ -515,6 +529,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KlaxonBlare) { S_Sound (self, CHAN_VOICE, "misc/alarm", 1, ATTN_NORM); } + return 0; } // Power Coupling ----------------------------------------------------------- @@ -578,6 +593,8 @@ IMPLEMENT_CLASS (AMeat) DEFINE_ACTION_FUNCTION(AActor, A_TossGib) { + PARAM_ACTION_PROLOGUE; + const char *gibtype = (self->flags & MF_NOBLOOD) ? "Junk" : "Meat"; AActor *gib = Spawn (gibtype, self->x, self->y, self->z + 24*FRACUNIT, ALLOW_REPLACE); angle_t an; @@ -585,7 +602,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_TossGib) if (gib == NULL) { - return; + return 0; } an = pr_gibtosser() << 24; @@ -594,37 +611,49 @@ DEFINE_ACTION_FUNCTION(AActor, A_TossGib) gib->velx = speed * finecosine[an >> ANGLETOFINESHIFT]; gib->vely = speed * finesine[an >> ANGLETOFINESHIFT]; gib->velz = (pr_gibtosser() & 15) << FRACBITS; + return 0; } //============================================================================ DEFINE_ACTION_FUNCTION(AActor, A_FLoopActiveSound) { + PARAM_ACTION_PROLOGUE; + if (self->ActiveSound != 0 && !(level.time & 7)) { S_Sound (self, CHAN_VOICE, self->ActiveSound, 1, ATTN_NORM); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_Countdown) { + PARAM_ACTION_PROLOGUE; + if (--self->reactiontime <= 0) { P_ExplodeMissile (self, NULL, NULL); self->flags &= ~MF_SKULLFLY; } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_LoopActiveSound) { + PARAM_ACTION_PROLOGUE; + if (self->ActiveSound != 0 && !S_IsActorPlayingSomething (self, CHAN_VOICE, -1)) { S_Sound (self, CHAN_VOICE|CHAN_LOOP, self->ActiveSound, 1, ATTN_NORM); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain) { + PARAM_ACTION_PROLOGUE; + sector_t *sec = self->Sector; if (self->z == sec->floorplane.ZatPoint (self->x, self->y)) @@ -643,6 +672,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain) self->vely += FixedMul (speed, finesine[finean]); } } + return 0; } //============================================================================ @@ -653,6 +683,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain) DEFINE_ACTION_FUNCTION(AActor, A_ClearSoundTarget) { + PARAM_ACTION_PROLOGUE; + AActor *actor; self->Sector->SoundTarget = NULL; @@ -660,11 +692,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_ClearSoundTarget) { actor->LastHeard = NULL; } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_ItBurnsItBurns) { + PARAM_ACTION_PROLOGUE; + S_Sound (self, CHAN_VOICE, "human/imonfire", 1, ATTN_NORM); if (self->player != NULL && self->player->mo == self) @@ -676,17 +711,23 @@ DEFINE_ACTION_FUNCTION(AActor, A_ItBurnsItBurns) self->player->playerstate = PST_LIVE; self->player->extralight = 3; } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_DropFire) { + PARAM_ACTION_PROLOGUE; + AActor *drop = Spawn("FireDroplet", self->x, self->y, self->z + 24*FRACUNIT, ALLOW_REPLACE); drop->velz = -FRACUNIT; P_RadiusAttack (self, self, 64, 64, NAME_Fire, false); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_CrispyPlayer) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL && self->player->mo == self) { self->player->playerstate = PST_DEAD; @@ -694,10 +735,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_CrispyPlayer) self->player->psprites[ps_weapon].state + (self->FindState("FireHandsLower") - self->FindState("FireHands"))); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_HandLower) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { pspdef_t *psp = &self->player->psprites[ps_weapon]; @@ -708,5 +752,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_HandLower) } if (self->player->extralight > 0) self->player->extralight--; } + return 0; } diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp index 6c53fa247..b4d35c94c 100644 --- a/src/g_strife/a_strifeweapons.cpp +++ b/src/g_strife/a_strifeweapons.cpp @@ -94,6 +94,8 @@ void P_DaggerAlert (AActor *target, AActor *emitter) DEFINE_ACTION_FUNCTION(AActor, A_JabDagger) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int damage; int pitch; @@ -129,6 +131,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_JabDagger) { S_Sound (self, CHAN_WEAPON, "misc/swish", 1, ATTN_NORM); } + return 0; } //============================================================================ @@ -139,6 +142,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_JabDagger) DEFINE_ACTION_FUNCTION(AActor, A_AlertMonsters) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { P_NoiseAlert(self, self); @@ -147,6 +152,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_AlertMonsters) { P_NoiseAlert (self->target, self); } + return 0; } // Poison Bolt -------------------------------------------------------------- @@ -186,12 +192,15 @@ int APoisonBolt::DoSpecialDamage (AActor *target, int damage) DEFINE_ACTION_FUNCTION(AActor, A_ClearFlash) { + PARAM_ACTION_PROLOGUE; + player_t *player = self->player; if (player == NULL) - return; + return 0; P_SetPsprite (player, ps_flash, NULL); + return 0; } //============================================================================ @@ -202,10 +211,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_ClearFlash) DEFINE_ACTION_FUNCTION(AActor, A_ShowElectricFlash) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { P_SetPsprite (self->player, ps_flash, self->player->ReadyWeapon->FindState(NAME_Flash)); } + return 0; } //============================================================================ @@ -216,19 +228,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_ShowElectricFlash) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireArrow) { + PARAM_ACTION_PROLOGUE; + PARAM_CLASS(ti, AActor); + angle_t savedangle; - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(ti, 0); - if (self->player == NULL) - return; + return 0; AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } if (ti) @@ -240,6 +252,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireArrow) self->angle = savedangle; S_Sound (self, CHAN_WEAPON, "weapons/xbowshoot", 1, ATTN_NORM); } + return 0; } // Assault Gun -------------------------------------------------------------- @@ -274,6 +287,8 @@ void P_StrifeGunShot (AActor *mo, bool accurate, angle_t pitch) DEFINE_ACTION_FUNCTION(AActor, A_FireAssaultGun) { + PARAM_ACTION_PROLOGUE; + bool accurate; S_Sound (self, CHAN_WEAPON, "weapons/assaultgun", 1, ATTN_NORM); @@ -284,7 +299,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireAssaultGun) if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } self->player->mo->PlayAttacking2 (); accurate = !self->player->refire; @@ -295,6 +310,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireAssaultGun) } P_StrifeGunShot (self, accurate, P_BulletSlope (self)); + return 0; } // Mini-Missile Launcher ---------------------------------------------------- @@ -307,17 +323,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireAssaultGun) DEFINE_ACTION_FUNCTION(AActor, A_FireMiniMissile) { + PARAM_ACTION_PROLOGUE; + player_t *player = self->player; angle_t savedangle; if (self->player == NULL) - return; + return 0; AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } savedangle = self->angle; @@ -325,6 +343,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMiniMissile) player->mo->PlayAttacking2 (); P_SpawnPlayerMissile (self, PClass::FindClass("MiniMissile")); self->angle = savedangle; + return 0; } //============================================================================ @@ -335,6 +354,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMiniMissile) DEFINE_ACTION_FUNCTION(AActor, A_RocketInFlight) { + PARAM_ACTION_PROLOGUE; + AActor *trail; S_Sound (self, CHAN_VOICE, "misc/missileinflight", 1, ATTN_NORM); @@ -344,6 +365,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RocketInFlight) { trail->velz = FRACUNIT; } + return 0; } // Flame Thrower ------------------------------------------------------------ @@ -356,8 +378,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_RocketInFlight) DEFINE_ACTION_FUNCTION(AActor, A_FlameDie) { + PARAM_ACTION_PROLOGUE; + self->flags |= MF_NOGRAVITY; self->velz = (pr_flamedie() & 3) << FRACBITS; + return 0; } //============================================================================ @@ -368,6 +393,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FlameDie) DEFINE_ACTION_FUNCTION(AActor, A_FireFlamer) { + PARAM_ACTION_PROLOGUE; + player_t *player = self->player; if (player != NULL) @@ -376,7 +403,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireFlamer) if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } player->mo->PlayAttacking2 (); } @@ -387,6 +414,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireFlamer) { self->velz += 5*FRACUNIT; } + return 0; } // Mauler ------------------------------------------------------------------- @@ -402,13 +430,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireFlamer) DEFINE_ACTION_FUNCTION(AActor, A_FireMauler1) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } // Strife apparently didn't show the player shooting. Let's fix that. self->player->mo->PlayAttacking2 (); @@ -431,6 +461,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMauler1) // original. P_LineAttack (self, angle, PLAYERMISSILERANGE, pitch, damage, NAME_Disintegrate, NAME_MaulerPuff); } + return 0; } //============================================================================ @@ -443,6 +474,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMauler1) DEFINE_ACTION_FUNCTION(AActor, A_FireMauler2Pre) { + PARAM_ACTION_PROLOGUE; + S_Sound (self, CHAN_WEAPON, "weapons/mauler2charge", 1, ATTN_NORM); if (self->player != NULL) @@ -450,6 +483,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMauler2Pre) self->player->psprites[ps_weapon].sx += pr_mauler2.Random2() << 10; self->player->psprites[ps_weapon].sy += pr_mauler2.Random2() << 10; } + return 0; } //============================================================================ @@ -462,19 +496,22 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMauler2Pre) DEFINE_ACTION_FUNCTION(AActor, A_FireMauler2) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } self->player->mo->PlayAttacking2 (); } P_SpawnPlayerMissile (self, PClass::FindClass("MaulerTorpedo")); P_DamageMobj (self, self, NULL, 20, self->DamageType); P_ThrustMobj (self, self->angle + ANGLE_180, 0x7D000); + return 0; } //============================================================================ @@ -489,6 +526,8 @@ AActor *P_SpawnSubMissile (AActor *source, const PClass *type, AActor *target); DEFINE_ACTION_FUNCTION(AActor, A_MaulerTorpedoWave) { + PARAM_ACTION_PROLOGUE; + AActor *wavedef = GetDefaultByName("MaulerTorpedoWave"); fixed_t savedz; self->angle += ANGLE_180; @@ -506,6 +545,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MaulerTorpedoWave) P_SpawnSubMissile (self, PClass::FindClass("MaulerTorpedoWave"), self->target); } self->z = savedz; + return 0; } AActor *P_SpawnSubMissile (AActor *source, const PClass *type, AActor *target) @@ -568,11 +608,16 @@ int APhosphorousFire::DoSpecialDamage (AActor *target, int damage) DEFINE_ACTION_FUNCTION(AActor, A_BurnArea) { + PARAM_ACTION_PROLOGUE; + P_RadiusAttack (self, self->target, 128, 128, self->DamageType, true); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_Burnination) { + PARAM_ACTION_PROLOGUE; + self->velz -= 8*FRACUNIT; self->velx += (pr_phburn.Random2 (3)) << FRACBITS; self->vely += (pr_phburn.Random2 (3)) << FRACBITS; @@ -624,6 +669,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Burnination) drop->flags |= MF_DROPPED; } } + return 0; } //============================================================================ @@ -634,25 +680,25 @@ DEFINE_ACTION_FUNCTION(AActor, A_Burnination) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireGrenade) { + PARAM_ACTION_PROLOGUE; + PARAM_CLASS(grenadetype, AActor); + PARAM_ANGLE(angleofs); + PARAM_STATE(flash) + player_t *player = self->player; AActor *grenade; angle_t an; fixed_t tworadii; AWeapon *weapon; - ACTION_PARAM_START(3); - ACTION_PARAM_CLASS(grenadetype, 0); - ACTION_PARAM_ANGLE(Angle, 1); - ACTION_PARAM_STATE(flash, 2); - if (player == NULL || grenadetype == NULL) - return; + return 0; if ((weapon = player->ReadyWeapon) == NULL) - return; + return 0; if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; P_SetPsprite (player, ps_flash, flash); @@ -662,7 +708,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireGrenade) grenade = P_SpawnSubMissile (self, grenadetype, self); self->z -= 32*FRACUNIT; if (grenade == NULL) - return; + return 0; if (grenade->SeeSound != 0) { @@ -676,11 +722,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireGrenade) grenade->x += FixedMul (finecosine[an], tworadii); grenade->y += FixedMul (finesine[an], tworadii); - an = self->angle + Angle; + an = self->angle + angleofs; an >>= ANGLETOFINESHIFT; grenade->x += FixedMul (finecosine[an], 15*FRACUNIT); grenade->y += FixedMul (finesine[an], 15*FRACUNIT); } + return 0; } // The Almighty Sigil! ------------------------------------------------------ @@ -771,12 +818,15 @@ AInventory *ASigil::CreateCopy (AActor *other) DEFINE_ACTION_FUNCTION(AActor, A_SelectPiece) { + PARAM_ACTION_PROLOGUE; + int pieces = MIN (static_cast<ASigil*>(self)->NumPieces, 5); if (pieces > 1) { self->SetState (self->FindState("Spawn")+pieces); } + return 0; } //============================================================================ @@ -794,15 +844,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_SelectPiece) DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilView) { + PARAM_ACTION_PROLOGUE; + int pieces; if (self->player == NULL) { - return; + return 0; } pieces = static_cast<ASigil*>(self->player->ReadyWeapon)->NumPieces; P_SetPsprite (self->player, ps_weapon, self->player->psprites[ps_weapon].state + pieces); + return 0; } //============================================================================ @@ -817,11 +870,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilView) DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilDown) { + PARAM_ACTION_PROLOGUE; + int pieces; if (self->player == NULL) { - return; + return 0; } pieces = static_cast<ASigil*>(self->player->ReadyWeapon)->DownPieces; static_cast<ASigil*>(self->player->ReadyWeapon)->DownPieces = 0; @@ -831,6 +886,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilDown) } P_SetPsprite (self->player, ps_weapon, self->player->psprites[ps_weapon].state + pieces); + return 0; } //============================================================================ @@ -843,15 +899,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilDown) DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilAttack) { + PARAM_ACTION_PROLOGUE; + int pieces; if (self->player == NULL) { - return; + return 0; } pieces = static_cast<ASigil*>(self->player->ReadyWeapon)->NumPieces; P_SetPsprite (self->player, ps_weapon, self->player->psprites[ps_weapon].state + 4*pieces - 3); + return 0; } //============================================================================ @@ -862,11 +921,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilAttack) DEFINE_ACTION_FUNCTION(AActor, A_SigilCharge) { + PARAM_ACTION_PROLOGUE; + S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); if (self->player != NULL) { self->player->extralight = 2; } + return 0; } //============================================================================ @@ -877,10 +939,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_SigilCharge) DEFINE_ACTION_FUNCTION(AActor, A_LightInverse) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { self->player->extralight = INT_MIN; } + return 0; } //============================================================================ @@ -891,12 +956,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightInverse) DEFINE_ACTION_FUNCTION(AActor, A_FireSigil1) { + PARAM_ACTION_PROLOGUE; + AActor *spot; player_t *player = self->player; AActor *linetarget; if (player == NULL || player->ReadyWeapon == NULL) - return; + return 0; P_DamageMobj (self, self, NULL, 1*4, 0, DMG_NO_ARMOR); S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); @@ -924,6 +991,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil1) spot->health = -1; spot->target = self; } + return 0; } //============================================================================ @@ -934,15 +1002,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil1) DEFINE_ACTION_FUNCTION(AActor, A_FireSigil2) { + PARAM_ACTION_PROLOGUE; + player_t *player = self->player; if (player == NULL || player->ReadyWeapon == NULL) - return; + return 0; P_DamageMobj (self, self, NULL, 2*4, 0, DMG_NO_ARMOR); S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); P_SpawnPlayerMissile (self, PClass::FindClass("SpectralLightningH1")); + return 0; } //============================================================================ @@ -953,12 +1024,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil2) DEFINE_ACTION_FUNCTION(AActor, A_FireSigil3) { + PARAM_ACTION_PROLOGUE; + AActor *spot; player_t *player = self->player; int i; if (player == NULL || player->ReadyWeapon == NULL) - return; + return 0; P_DamageMobj (self, self, NULL, 3*4, 0, DMG_NO_ARMOR); S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); @@ -974,6 +1047,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil3) } } self->angle -= (ANGLE_180/20)*10; + return 0; } //============================================================================ @@ -984,12 +1058,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil3) DEFINE_ACTION_FUNCTION(AActor, A_FireSigil4) { + PARAM_ACTION_PROLOGUE; + AActor *spot; player_t *player = self->player; AActor *linetarget; if (player == NULL || player->ReadyWeapon == NULL) - return; + return 0; P_DamageMobj (self, self, NULL, 4*4, 0, DMG_NO_ARMOR); S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); @@ -1012,6 +1088,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil4) spot->vely += FixedMul (spot->Speed, finesine[self->angle >> ANGLETOFINESHIFT]); } } + return 0; } //============================================================================ @@ -1022,15 +1099,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil4) DEFINE_ACTION_FUNCTION(AActor, A_FireSigil5) { + PARAM_ACTION_PROLOGUE; + player_t *player = self->player; if (player == NULL || player->ReadyWeapon == NULL) - return; + return 0; P_DamageMobj (self, self, NULL, 5*4, 0, DMG_NO_ARMOR); S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); P_SpawnPlayerMissile (self, PClass::FindClass("SpectralLightningBigBall1")); + return 0; } //============================================================================ diff --git a/src/g_strife/a_templar.cpp b/src/g_strife/a_templar.cpp index afdac2e15..0dd95090b 100644 --- a/src/g_strife/a_templar.cpp +++ b/src/g_strife/a_templar.cpp @@ -13,13 +13,15 @@ static FRandom pr_templar ("Templar"); DEFINE_ACTION_FUNCTION(AActor, A_TemplarAttack) { + PARAM_ACTION_PROLOGUE; + int damage; angle_t angle; int pitch; int pitchdiff; if (self->target == NULL) - return; + return 0; S_Sound (self, CHAN_WEAPON, "templar/shoot", 1, ATTN_NORM); A_FaceTarget (self); @@ -32,4 +34,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_TemplarAttack) pitchdiff = pr_templar.Random2() * 332063; P_LineAttack (self, angle, MISSILERANGE+64*FRACUNIT, pitch+pitchdiff, damage, NAME_Disintegrate, NAME_MaulerPuff); } + return 0; } diff --git a/src/g_strife/a_thingstoblowup.cpp b/src/g_strife/a_thingstoblowup.cpp index 52cb1d3e5..7350ab1f5 100644 --- a/src/g_strife/a_thingstoblowup.cpp +++ b/src/g_strife/a_thingstoblowup.cpp @@ -18,30 +18,36 @@ extern const PClass *QuestItemClasses[31]; DEFINE_ACTION_FUNCTION(AActor, A_Bang4Cloud) { + PARAM_ACTION_PROLOGUE; + fixed_t spawnx, spawny; spawnx = self->x + (pr_bang4cloud.Random2() & 3) * 10240; spawny = self->y + (pr_bang4cloud.Random2() & 3) * 10240; Spawn("Bang4Cloud", spawnx, spawny, self->z, ALLOW_REPLACE); + return 0; } // ------------------------------------------------------------------- DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveQuestItem) { - ACTION_PARAM_START(1); - ACTION_PARAM_INT(questitem, 0); + PARAM_ACTION_PROLOGUE; + PARAM_INT(questitem); // Give one of these quest items to every player in the game - for (int i = 0; i < MAXPLAYERS; ++i) + if (questitem >= 0 && questitem < countof(QuestItemClasses)) { - if (playeringame[i]) + for (int i = 0; i < MAXPLAYERS; ++i) { - AInventory *item = static_cast<AInventory *>(Spawn (QuestItemClasses[questitem-1], 0,0,0, NO_REPLACE)); - if (!item->CallTryPickup (players[i].mo)) + if (playeringame[i]) { - item->Destroy (); + AInventory *item = static_cast<AInventory *>(Spawn (QuestItemClasses[questitem - 1], 0,0,0, NO_REPLACE)); + if (!item->CallTryPickup (players[i].mo)) + { + item->Destroy (); + } } } } @@ -55,20 +61,26 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveQuestItem) { C_MidPrint (SmallFont, name); } + return 0; } // PowerCrystal ------------------------------------------------------------------- DEFINE_ACTION_FUNCTION(AActor, A_ExtraLightOff) { + PARAM_ACTION_PROLOGUE; + if (self->target != NULL && self->target->player != NULL) { self->target->player->extralight = 0; } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_Explode512) { + PARAM_ACTION_PROLOGUE; + P_RadiusAttack (self, self->target, 512, 512, NAME_None, true); if (self->target != NULL && self->target->player != NULL) { @@ -81,10 +93,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_Explode512) // Strife didn't do this next part, but it looks good self->RenderStyle = STYLE_Add; + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_LightGoesOut) { + PARAM_ACTION_PROLOGUE; + AActor *foo; sector_t *sec = self->Sector; vertex_t *spot; @@ -106,4 +121,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightGoesOut) foo->velz = (7 + (pr_lightout() & 3)) << FRACBITS; } } + return 0; } diff --git a/src/info.cpp b/src/info.cpp index 0edcfea5e..3bb0ab482 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -51,79 +51,13 @@ extern void LoadActors (); -int CallDecorateAction(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) -{ - assert(numparam == 6); - actionf_p action = (actionf_p)param[5].a; - action((AActor *)param[0].a, (AActor *)param[1].a, (FState *)param[2].a, param[3].i, (StateCallData *)param[4].a); - return 0; -} - -void FState::SetAction(PSymbolActionFunction *func, bool setdefaultparams) -{ - if (func != NULL) - { - // All generated functions use this code. - static const VM_UBYTE codetemplate[] = - { - OP_PARAM, 0, REGT_POINTER, 0, - OP_PARAM, 0, REGT_POINTER, 1, - OP_PARAM, 0, REGT_POINTER, 2, - OP_PARAM, 0, REGT_INT, 0, - OP_PARAM, 0, REGT_POINTER, 3, - OP_PARAM, 0, REGT_POINTER|REGT_KONST, 0, - OP_CALL_K, 1, 6, 0, - OP_RET, 0, REGT_NIL, 0 - }; - - // Find the CallDecorateAction function. If not found, create it and install it - // in Actor. - VMFunction *callfunc; - PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol("CallDecorateAction", false); - if (sym == NULL) - { - PSymbolVMFunction *symfunc = new PSymbolVMFunction("CallDecorateAction"); - VMNativeFunction *calldec = new VMNativeFunction(CallDecorateAction); - symfunc->Function = calldec; - sym = symfunc; - RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); - } - assert(sym->SymbolType == SYM_VMFunction); - assert(((PSymbolVMFunction *)sym)->Function != NULL); - callfunc = ((PSymbolVMFunction *)sym)->Function; - - // Create a function for this state. - VMScriptFunction *vmfunc = new VMScriptFunction; - vmfunc->Alloc(sizeof(codetemplate)/sizeof(VMOP), 0, 0, 0, 2); - memcpy(vmfunc->Code, codetemplate, sizeof(codetemplate)); - FVoidObj *konsta = vmfunc->KonstA; - VM_ATAG *atag = vmfunc->KonstATags(); - konsta[0].v = (void *)func->Function; - konsta[1].o = callfunc; - atag[0] = ATAG_GENERIC; - atag[1] = ATAG_OBJECT; - vmfunc->NumRegA = 4; - vmfunc->NumRegD = 1; - vmfunc->MaxParam = 6; - vmfunc->NumArgs = 5; - ActionFunc = vmfunc; - - if (setdefaultparams) ParameterIndex = func->defaultparameterindex+1; - } - else - { - ActionFunc = NULL; - if (setdefaultparams) ParameterIndex = 0; - } -} - bool FState::CallAction(AActor *self, AActor *stateowner, StateCallData *statecall) { if (ActionFunc != NULL) { //ActionFunc(self, stateowner, this, ParameterIndex-1, statecall); VMFrameStack stack; - VMValue params[5] = { self, stateowner, this, ParameterIndex - 1, VMValue(statecall, ATAG_STATE) }; + VMValue params[4] = { self, stateowner, VMValue(this, ATAG_STATE), statecall }; stack.Call(ActionFunc, params, countof(params), NULL, 0, NULL); return true; } diff --git a/src/info.h b/src/info.h index 9ce3e662e..66e00b7af 100644 --- a/src/info.h +++ b/src/info.h @@ -62,7 +62,6 @@ struct FState BYTE DefineFlags; // Unused byte so let's use it during state creation. FState *NextState; VMFunction *ActionFunc; - int ParameterIndex; inline int GetFrame() const { @@ -92,7 +91,7 @@ struct FState { Frame = (Frame & SF_FULLBRIGHT) | (frame-'A'); } - void SetAction(PSymbolActionFunction *func, bool setdefaultparams = true); + void SetAction(VMFunction *func) { ActionFunc = func; } bool CallAction(AActor *self, AActor *stateowner, StateCallData *statecall = NULL); static const PClass *StaticFindStateOwner (const FState *state); static const PClass *StaticFindStateOwner (const FState *state, const FActorInfo *info); @@ -190,4 +189,21 @@ extern FDoomEdMap DoomEdMap; int GetSpriteIndex(const char * spritename); TArray<FName> &MakeStateNameList(const char * fname); +// Standard parameters for all action functons +// self - Actor this action is to operate on (player if a weapon) +// stateowner - Actor this action really belongs to (may be a weapon) +// callingstate - State this action was called from +// statecall - CustomInventory stuff +#define PARAM_ACTION_PROLOGUE_TYPE(type) \ + PARAM_PROLOGUE; \ + PARAM_OBJECT (self, type); \ + PARAM_OBJECT_OPT (stateowner, AActor) { stateowner = self; } \ + PARAM_STATE_OPT (callingstate) { callingstate = NULL; } \ + PARAM_POINTER_OPT(statecall, StateCallData) { statecall = NULL; } + +#define PARAM_ACTION_PROLOGUE PARAM_ACTION_PROLOGUE_TYPE(AActor) + +// Number of action paramaters +#define NAP 4 + #endif // __INFO_H__ diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 7e3bb0b26..5e24f1fbc 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -1688,10 +1688,12 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params) // DEFINE_ACTION_FUNCTION(AActor, A_Look) { + PARAM_ACTION_PROLOGUE; + AActor *targ; if (self->flags5 & MF5_INCONVERSATION) - return; + return 0; // [RH] Set goal now if appropriate if (self->special == Thing_SetGoal && self->args[0] == 0) @@ -1723,7 +1725,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look) if (targ && targ->player && (targ->player->cheats & CF_NOTARGET)) { - return; + return 0; } } @@ -1767,7 +1769,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look) } if (!P_LookForPlayers (self, self->flags4 & MF4_LOOKALLAROUND, NULL)) - return; + return 0; // go into chase state seeyou: @@ -1793,6 +1795,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look) { self->SetState (self->SeeState); } + return 0; } @@ -1805,30 +1808,32 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) { - ACTION_PARAM_START(6); - ACTION_PARAM_INT(flags, 0); - ACTION_PARAM_FIXED(minseedist, 1); - ACTION_PARAM_FIXED(maxseedist, 2); - ACTION_PARAM_FIXED(maxheardist, 3); - ACTION_PARAM_ANGLE(fov, 4); - ACTION_PARAM_STATE(seestate, 5); + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_FIXED_OPT (minseedist) { minseedist = 0; } + PARAM_FIXED_OPT (maxseedist) { maxseedist = 0; } + PARAM_FIXED_OPT (maxheardist) { maxheardist = 0; } + PARAM_ANGLE_OPT (fov) { fov = 0; } + PARAM_STATE_OPT (seestate) { seestate = NULL; } AActor *targ = NULL; // Shuts up gcc fixed_t dist; - FLookExParams params = {fov, minseedist, maxseedist, maxheardist, flags, seestate }; + FLookExParams params = { fov, minseedist, maxseedist, maxheardist, flags, seestate }; if (self->flags5 & MF5_INCONVERSATION) - return; + return 0; // [RH] Set goal now if appropriate if (self->special == Thing_SetGoal && self->args[0] == 0) { - NActorIterator iterator (NAME_PatrolPoint, self->args[1]); + NActorIterator iterator(NAME_PatrolPoint, self->args[1]); self->special = 0; self->goal = iterator.Next (); self->reactiontime = self->args[2] * TICRATE + level.maptime; - if (self->args[3] == 0) self->flags5 &=~ MF5_CHASEGOAL; - else self->flags5 |= MF5_CHASEGOAL; + if (self->args[3] == 0) + self->flags5 &= ~MF5_CHASEGOAL; + else + self->flags5 |= MF5_CHASEGOAL; } self->threshold = 0; // any shot will wake up @@ -1851,8 +1856,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) } else { - dist = P_AproxDistance (targ->x - self->x, - targ->y - self->y); + dist = P_AproxDistance (targ->x - self->x, targ->y - self->y); // [KS] If the target is too far away, don't respond to the sound. if (maxheardist && dist > maxheardist) @@ -1866,7 +1870,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) if (targ && targ->player && (targ->player->cheats & CF_NOTARGET)) { - return; + return 0; } } @@ -1923,8 +1927,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) { if (self->flags & MF_AMBUSH) { - dist = P_AproxDistance (self->target->x - self->x, - self->target->y - self->y); + dist = P_AproxDistance (self->target->x - self->x, self->target->y - self->y); if (P_CheckSight (self, self->target, 2) && (!minseedist || dist > minseedist) && (!maxseedist || dist < maxseedist)) @@ -1941,11 +1944,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) if (!(flags & LOF_NOSIGHTCHECK)) { if (!P_LookForPlayers(self, true, ¶ms)) - return; + return 0; } else { - return; + return 0; } // go into chase state @@ -1979,6 +1982,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) self->SetState (self->SeeState); } } + return 0; } // [KS] *** End additions by me *** @@ -1990,20 +1994,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) //========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_Wander) { + PARAM_ACTION_PROLOGUE; + // [RH] Strife probably clears this flag somewhere, but I couldn't find where. // This seems as good a place as any. self->flags4 &= ~MF4_INCOMBAT; if (self->flags5 & MF5_INCONVERSATION) - return; + return 0; if (self->flags4 & MF4_STANDSTILL) - return; + return 0; if (self->reactiontime != 0) { self->reactiontime--; - return; + return 0; } // turn towards movement direction if not there yet @@ -2026,6 +2032,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Wander) P_RandomChaseDir (self); self->movecount += 5; } + return 0; } @@ -2036,10 +2043,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_Wander) //========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_Look2) { + PARAM_ACTION_PROLOGUE; + AActor *targ; if (self->flags5 & MF5_INCONVERSATION) - return; + return 0; self->threshold = 0; targ = self->LastHeard; @@ -2062,7 +2071,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look2) self->target = targ; self->threshold = 10; self->SetState (self->SeeState); - return; + return 0; } else { @@ -2070,7 +2079,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look2) goto nosee; self->SetState (self->SeeState); self->flags4 |= MF4_INCOMBAT; - return; + return 0; } } nosee: @@ -2082,6 +2091,7 @@ nosee: { self->SetState (self->SpawnState + 3); } + return 0; } //============================================================================= @@ -2097,7 +2107,7 @@ nosee: //============================================================================= #define CLASS_BOSS_STRAFE_RANGE 64*10*FRACUNIT -void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missilestate, bool playactive, bool nightmarefast, bool dontmove) +void A_DoChase (VMFrameStack *stack, AActor *actor, bool fastchase, FState *meleestate, FState *missilestate, bool playactive, bool nightmarefast, bool dontmove) { int delta; @@ -2607,53 +2617,60 @@ enum ChaseFlags DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Chase) { - ACTION_PARAM_START(3); - ACTION_PARAM_STATE(melee, 0); - ACTION_PARAM_STATE(missile, 1); - ACTION_PARAM_INT(flags, 2); + PARAM_ACTION_PROLOGUE; + PARAM_STATE_OPT (melee) { melee = NULL; } + PARAM_STATE_OPT (missile) { missile = NULL; } + PARAM_INT_OPT (flags) { flags = 0; } - if (melee != (FState*)-1) + if (numparam >= NAP + 1) { - if (flags & CHF_RESURRECT && P_CheckForResurrection(self, false)) return; + if ((flags & CHF_RESURRECT) && P_CheckForResurrection(self, false)) + return 0; - A_DoChase(self, !!(flags&CHF_FASTCHASE), melee, missile, !(flags&CHF_NOPLAYACTIVE), + A_DoChase(stack, self, !!(flags&CHF_FASTCHASE), melee, missile, !(flags&CHF_NOPLAYACTIVE), !!(flags&CHF_NIGHTMAREFAST), !!(flags&CHF_DONTMOVE)); } else // this is the old default A_Chase { - A_DoChase (self, false, self->MeleeState, self->MissileState, true, !!(gameinfo.gametype & GAME_Raven), false); + A_DoChase(stack, self, false, self->MeleeState, self->MissileState, true, !!(gameinfo.gametype & GAME_Raven), false); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_FastChase) { - A_DoChase (self, true, self->MeleeState, self->MissileState, true, true, false); + PARAM_ACTION_PROLOGUE; + A_DoChase(stack, self, true, self->MeleeState, self->MissileState, true, true, false); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_VileChase) { + PARAM_ACTION_PROLOGUE; if (!P_CheckForResurrection(self, true)) - A_DoChase (self, false, self->MeleeState, self->MissileState, true, !!(gameinfo.gametype & GAME_Raven), false); + A_DoChase(stack, self, false, self->MeleeState, self->MissileState, true, !!(gameinfo.gametype & GAME_Raven), false); + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ExtChase) { - ACTION_PARAM_START(4); - ACTION_PARAM_BOOL(domelee, 0); - ACTION_PARAM_BOOL(domissile, 1); - ACTION_PARAM_BOOL(playactive, 2); - ACTION_PARAM_BOOL(nightmarefast, 3); + PARAM_ACTION_PROLOGUE; + PARAM_BOOL (domelee); + PARAM_BOOL (domissile); + PARAM_BOOL_OPT (playactive) { playactive = true; } + PARAM_BOOL_OPT (nightmarefast) { nightmarefast = false; } // Now that A_Chase can handle state label parameters, this function has become rather useless... - A_DoChase(self, false, - domelee ? self->MeleeState:NULL, domissile ? self->MissileState:NULL, + A_DoChase(stack, self, false, + domelee ? self->MeleeState : NULL, domissile ? self->MissileState : NULL, playactive, nightmarefast, false); + return 0; } // for internal use -void A_Chase(AActor *self) +void A_Chase(VMFrameStack *stack, AActor *self) { - A_DoChase (self, false, self->MeleeState, self->MissileState, true, !!(gameinfo.gametype & GAME_Raven), false); + A_DoChase(stack, self, false, self->MeleeState, self->MissileState, true, !!(gameinfo.gametype & GAME_Raven), false); } //============================================================================= @@ -2673,8 +2690,7 @@ void A_FaceTarget (AActor *self) } self->flags &= ~MF_AMBUSH; - self->angle = R_PointToAngle2 (self->x, self->y, - self->target->x, self->target->y); + self->angle = R_PointToAngle2 (self->x, self->y, self->target->x, self->target->y); if (self->target->flags & MF_SHADOW) { @@ -2684,7 +2700,9 @@ void A_FaceTarget (AActor *self) DEFINE_ACTION_FUNCTION(AActor, A_FaceTarget) { + PARAM_ACTION_PROLOGUE; A_FaceTarget(self); + return 0; } //=========================================================================== @@ -2696,8 +2714,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_FaceTarget) //=========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail) { + PARAM_ACTION_PROLOGUE; + if (!self->target) - return; + return 0; // [RH] Andy Baker's stealth monsters if (self->flags & MF_STEALTH) @@ -2726,10 +2746,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail) } P_RailAttack (self, self->GetMissileDamage (0, 1), 0); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_Scream) { + PARAM_ACTION_PROLOGUE; if (self->DeathSound) { // Check for bosses. @@ -2743,14 +2765,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_Scream) S_Sound (self, CHAN_VOICE, self->DeathSound, 1, ATTN_NORM); } } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_XScream) { + PARAM_ACTION_PROLOGUE; if (self->player) S_Sound (self, CHAN_VOICE, "*gibbed", 1, ATTN_NORM); else S_Sound (self, CHAN_VOICE, "misc/gibbed", 1, ATTN_NORM); + return 0; } //=========================================================================== @@ -2761,8 +2786,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_XScream) DEFINE_ACTION_FUNCTION(AActor, A_ScreamAndUnblock) { + PARAM_ACTION_PROLOGUE; CALL_ACTION(A_Scream, self); CALL_ACTION(A_NoBlocking, self); + return 0; } //=========================================================================== @@ -2773,10 +2800,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_ScreamAndUnblock) DEFINE_ACTION_FUNCTION(AActor, A_ActiveSound) { + PARAM_ACTION_PROLOGUE; if (self->ActiveSound) { S_Sound (self, CHAN_VOICE, self->ActiveSound, 1, ATTN_NORM); } + return 0; } //=========================================================================== @@ -2787,8 +2816,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_ActiveSound) DEFINE_ACTION_FUNCTION(AActor, A_ActiveAndUnblock) { + PARAM_ACTION_PROLOGUE; CALL_ACTION(A_ActiveSound, self); CALL_ACTION(A_NoBlocking, self); + return 0; } //--------------------------------------------------------------------------- @@ -2921,6 +2952,8 @@ void P_TossItem (AActor *item) DEFINE_ACTION_FUNCTION(AActor, A_Pain) { + PARAM_ACTION_PROLOGUE; + // [RH] Vary player pain sounds depending on health (ala Quake2) if (self->player && self->player->morphTics == 0) { @@ -2962,15 +2995,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_Pain) { S_Sound (self, CHAN_VOICE, self->PainSound, 1, ATTN_NORM); } + return 0; } // killough 11/98: kill an object DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Die) { - ACTION_PARAM_START(1); - ACTION_PARAM_NAME(damagetype, 0); + PARAM_ACTION_PROLOGUE; + PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } P_DamageMobj (self, NULL, NULL, self->health, damagetype, DMG_FORCED); + return 0; } // @@ -2980,12 +3015,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Die) DEFINE_ACTION_FUNCTION(AActor, A_Detonate) { - int damage = self->GetMissileDamage (0, 1); + PARAM_ACTION_PROLOGUE; + int damage = self->GetMissileDamage(0, 1); P_RadiusAttack (self, self->target, damage, damage, self->DamageType, true); if (self->z <= self->floorz + (damage << FRACBITS)) { P_HitFloor (self); } + return 0; } bool CheckBossDeath (AActor *actor) @@ -3022,7 +3059,7 @@ bool CheckBossDeath (AActor *actor) // A_BossDeath // Possibly trigger special effects if on a boss level // -DEFINE_ACTION_FUNCTION(AActor, A_BossDeath) +void A_BossDeath(AActor *self) { FName mytype = self->GetClass()->TypeName; @@ -3118,6 +3155,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_BossDeath) G_ExitLevel (0, false); } +DEFINE_ACTION_FUNCTION(AActor, A_BossDeath) +{ + PARAM_ACTION_PROLOGUE; + A_BossDeath(self); + return 0; +} + //---------------------------------------------------------------------------- // // PROC P_Massacre @@ -3191,6 +3235,7 @@ bool A_RaiseMobj (AActor *actor, fixed_t speed) DEFINE_ACTION_FUNCTION(AActor, A_ClassBossHealth) { + PARAM_ACTION_PROLOGUE; if (multiplayer && !deathmatch) // co-op only { if (!self->special1) @@ -3199,4 +3244,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_ClassBossHealth) self->special1 = true; // has been initialized } } + return 0; } diff --git a/src/p_enemy.h b/src/p_enemy.h index b26360631..8dc6c5a4b 100644 --- a/src/p_enemy.h +++ b/src/p_enemy.h @@ -64,9 +64,9 @@ DECLARE_ACTION(A_NoBlocking) DECLARE_ACTION(A_Scream) DECLARE_ACTION(A_FreezeDeath) DECLARE_ACTION(A_FreezeDeathChunks) -DECLARE_ACTION(A_BossDeath) +void A_BossDeath(AActor *self); -void A_Chase(AActor *self); +void A_Chase(VMFrameStack *stack, AActor *self); void A_FaceTarget (AActor *actor); bool A_RaiseMobj (AActor *, fixed_t speed); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index b070adef1..6e9272ca2 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1009,7 +1009,7 @@ bool AActor::Grind(bool items) { if (this->flags4 & MF4_BOSSDEATH) { - CALL_ACTION(A_BossDeath, this); + A_BossDeath(this); } flags &= ~MF_SOLID; flags3 |= MF3_DONTGIB; @@ -1027,7 +1027,7 @@ bool AActor::Grind(bool items) { if (this->flags4 & MF4_BOSSDEATH) { - CALL_ACTION(A_BossDeath, this); + A_BossDeath(this); } const PClass *i = PClass::FindClass("RealGibs"); diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index ee287a8f1..7faf9b1b4 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -424,13 +424,16 @@ enum EWRF_Options DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady) { - ACTION_PARAM_START(1); - ACTION_PARAM_INT(paramflags, 0); + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT(flags) { flags = 0; } - if (!(paramflags & WRF_NoSwitch)) DoReadyWeaponToSwitch(self); - if ((paramflags & WRF_NoFire) != WRF_NoFire) DoReadyWeaponToFire(self, - (!(paramflags & WRF_NoPrimary)), (!(paramflags & WRF_NoSecondary))); - if (!(paramflags & WRF_NoBob)) DoReadyWeaponToBob(self); + if (!(flags & WRF_NoSwitch)) + DoReadyWeaponToSwitch(self); + if ((flags & WRF_NoFire) != WRF_NoFire) + DoReadyWeaponToFire(self, !(flags & WRF_NoPrimary), !(flags & WRF_NoSecondary)); + if (!(flags & WRF_NoBob)) + DoReadyWeaponToBob(self); + return 0; } //--------------------------------------------------------------------------- @@ -509,11 +512,13 @@ void P_CheckWeaponSwitch (player_t *player) DEFINE_ACTION_FUNCTION(AInventory, A_ReFire) { + PARAM_ACTION_PROLOGUE; + player_t *player = self->player; if (NULL == player) { - return; + return 0; } if ((player->cmd.ucmd.buttons&BT_ATTACK) && !player->ReadyWeapon->bAltFire @@ -535,16 +540,19 @@ DEFINE_ACTION_FUNCTION(AInventory, A_ReFire) player->ReadyWeapon->CheckAmmo (player->ReadyWeapon->bAltFire ? AWeapon::AltFire : AWeapon::PrimaryFire, true); } + return 0; } DEFINE_ACTION_FUNCTION(AInventory, A_ClearReFire) { + PARAM_ACTION_PROLOGUE; player_t *player = self->player; if (NULL != player) { player->refire = 0; } + return 0; } //--------------------------------------------------------------------------- @@ -559,12 +567,15 @@ DEFINE_ACTION_FUNCTION(AInventory, A_ClearReFire) DEFINE_ACTION_FUNCTION(AInventory, A_CheckReload) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { self->player->ReadyWeapon->CheckAmmo ( self->player->ReadyWeapon->bAltFire ? AWeapon::AltFire : AWeapon::PrimaryFire, true); } + return 0; } //--------------------------------------------------------------------------- @@ -575,12 +586,14 @@ DEFINE_ACTION_FUNCTION(AInventory, A_CheckReload) DEFINE_ACTION_FUNCTION(AInventory, A_Lower) { + PARAM_ACTION_PROLOGUE; + player_t *player = self->player; pspdef_t *psp; if (NULL == player) { - return; + return 0; } psp = &player->psprites[ps_weapon]; if (player->morphTics || player->cheats & CF_INSTANTWEAPSWITCH) @@ -593,17 +606,17 @@ DEFINE_ACTION_FUNCTION(AInventory, A_Lower) } if (psp->sy < WEAPONBOTTOM) { // Not lowered all the way yet - return; + return 0; } if (player->playerstate == PST_DEAD) { // Player is dead, so don't bring up a pending weapon psp->sy = WEAPONBOTTOM; - return; + return 0; } if (player->health <= 0) { // Player is dead, so keep the weapon off screen P_SetPsprite (player, ps_weapon, NULL); - return; + return 0; } /* if (player->PendingWeapon != WP_NOCHANGE) { // [RH] Make sure we're actually changing weapons. @@ -612,6 +625,7 @@ DEFINE_ACTION_FUNCTION(AInventory, A_Lower) // [RH] Clear the flash state. Only needed for Strife. P_SetPsprite (player, ps_flash, NULL); P_BringUpWeapon (player); + return 0; } //--------------------------------------------------------------------------- @@ -622,27 +636,29 @@ DEFINE_ACTION_FUNCTION(AInventory, A_Lower) DEFINE_ACTION_FUNCTION(AInventory, A_Raise) { + PARAM_ACTION_PROLOGUE; + if (self == NULL) { - return; + return 0; } player_t *player = self->player; pspdef_t *psp; if (NULL == player) { - return; + return 0; } if (player->PendingWeapon != WP_NOCHANGE) { P_SetPsprite (player, ps_weapon, player->ReadyWeapon->GetDownState()); - return; + return 0; } psp = &player->psprites[ps_weapon]; psp->sy -= RAISESPEED; if (psp->sy > WEAPONTOP) { // Not raised all the way yet - return; + return 0; } psp->sy = WEAPONTOP; if (player->ReadyWeapon != NULL) @@ -653,6 +669,7 @@ DEFINE_ACTION_FUNCTION(AInventory, A_Raise) { player->psprites[ps_weapon].state = NULL; } + return 0; } @@ -663,11 +680,12 @@ DEFINE_ACTION_FUNCTION(AInventory, A_Raise) // DEFINE_ACTION_FUNCTION(AInventory, A_GunFlash) { + PARAM_ACTION_PROLOGUE; player_t *player = self->player; if (NULL == player) { - return; + return 0; } player->mo->PlayAttacking2 (); @@ -675,6 +693,7 @@ DEFINE_ACTION_FUNCTION(AInventory, A_GunFlash) if (player->ReadyWeapon->bAltFire) flash = player->ReadyWeapon->FindState(NAME_AltFlash); if (flash == NULL) flash = player->ReadyWeapon->FindState(NAME_Flash); P_SetPsprite (player, ps_flash, flash); + return 0; } @@ -740,37 +759,47 @@ void P_GunShot (AActor *mo, bool accurate, const PClass *pufftype, angle_t pitch DEFINE_ACTION_FUNCTION(AInventory, A_Light0) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { self->player->extralight = 0; } + return 0; } DEFINE_ACTION_FUNCTION(AInventory, A_Light1) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { self->player->extralight = 1; } + return 0; } DEFINE_ACTION_FUNCTION(AInventory, A_Light2) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { self->player->extralight = 2; } + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_Light) { - ACTION_PARAM_START(1); - ACTION_PARAM_INT(light, 0); + PARAM_ACTION_PROLOGUE; + PARAM_INT(light); if (self->player != NULL) { self->player->extralight = clamp<int>(light, 0, 20); } + return 0; } //------------------------------------------------------------------------ diff --git a/src/p_user.cpp b/src/p_user.cpp index 014d837d4..a99a0d4b5 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1249,6 +1249,8 @@ void APlayerPawn::TweakSpeeds (int &forward, int &side) DEFINE_ACTION_FUNCTION(AActor, A_PlayerScream) { + PARAM_ACTION_PROLOGUE; + int sound = 0; int chan = CHAN_VOICE; @@ -1262,7 +1264,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PlayerScream) { S_Sound (self, CHAN_VOICE, "*death", 1, ATTN_NORM); } - return; + return 0; } // Handle the different player death screams @@ -1311,6 +1313,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PlayerScream) } } S_Sound (self, chan, sound, 1, ATTN_NORM); + return 0; } @@ -1322,17 +1325,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_PlayerScream) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SkullPop) { - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(spawntype, 0); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT(spawntype, APlayerChunk) { spawntype = NULL; } APlayerPawn *mo; player_t *player; // [GRB] Parameterized version - if (!spawntype || !spawntype->IsDescendantOf (RUNTIME_CLASS (APlayerChunk))) + if (spawntype == NULL || !spawntype->IsDescendantOf(RUNTIME_CLASS(APlayerChunk))) { spawntype = PClass::FindClass("BloodySkull"); - if (spawntype == NULL) return; + if (spawntype == NULL) return 0; } self->flags &= ~MF_SOLID; @@ -1357,6 +1360,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SkullPop) } player->damagecount = 32; } + return 0; } //---------------------------------------------------------------------------- @@ -1367,10 +1371,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SkullPop) DEFINE_ACTION_FUNCTION(AActor, A_CheckPlayerDone) { + PARAM_ACTION_PROLOGUE; + if (self->player == NULL) { - self->Destroy (); + self->Destroy(); } + return 0; } //=========================================================================== @@ -1384,7 +1391,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckPlayerDone) void P_CheckPlayerSprites() { - for(int i=0; i<MAXPLAYERS; i++) + for (int i = 0; i < MAXPLAYERS; i++) { player_t * player = &players[i]; APlayerPawn * mo = player->mo; diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 099565925..be1023039 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -802,7 +802,7 @@ static void CalcPolyobjSoundOrg(const FPolyObj *poly, fixed_t *x, fixed_t *y, fi //========================================================================== static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyObj *poly, - const FVector3 *pt, int channel, FSoundID sound_id, float volume, float attenuation) + const FVector3 *pt, int channel, FSoundID sound_id, double volume, double attenuation) { sfxinfo_t *sfx; int chanflags; @@ -860,7 +860,7 @@ static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyO sfx = &S_sfx[sound_id]; // Scale volume according to SNDINFO data. - volume = MIN(volume * sfx->Volume, 1.f); + volume = MIN(volume * sfx->Volume, 1.0); if (volume <= 0) return NULL; @@ -1037,11 +1037,11 @@ static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyO { SoundListener listener; S_SetListener(listener, players[consoleplayer].camera); - chan = (FSoundChan*)GSnd->StartSound3D (sfx->data, &listener, volume, rolloff, attenuation, pitch, basepriority, pos, vel, channel, startflags, NULL); + chan = (FSoundChan*)GSnd->StartSound3D (sfx->data, &listener, float(volume), rolloff, float(attenuation), pitch, basepriority, pos, vel, channel, startflags, NULL); } else { - chan = (FSoundChan*)GSnd->StartSound (sfx->data, volume, pitch, startflags, NULL); + chan = (FSoundChan*)GSnd->StartSound (sfx->data, float(volume), pitch, startflags, NULL); } } if (chan == NULL && (chanflags & CHAN_LOOP)) @@ -1063,13 +1063,13 @@ static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyO chan->OrgID = FSoundID(org_id); chan->SfxInfo = sfx; chan->EntChannel = channel; - chan->Volume = volume; + chan->Volume = float(volume); chan->ChanFlags |= chanflags; chan->NearLimit = near_limit; chan->LimitRange = limit_range; chan->Pitch = pitch; chan->Priority = basepriority; - chan->DistanceScale = attenuation; + chan->DistanceScale = float(attenuation); chan->SourceType = type; switch (type) { @@ -1156,7 +1156,7 @@ void S_RestartSound(FSoundChan *chan) // //========================================================================== -void S_Sound (int channel, FSoundID sound_id, float volume, float attenuation) +void S_Sound (int channel, FSoundID sound_id, double volume, double attenuation) { S_StartSound (NULL, NULL, NULL, NULL, channel, sound_id, volume, attenuation); } @@ -1167,7 +1167,7 @@ void S_Sound (int channel, FSoundID sound_id, float volume, float attenuation) // //========================================================================== -void S_Sound (AActor *ent, int channel, FSoundID sound_id, float volume, float attenuation) +void S_Sound (AActor *ent, int channel, FSoundID sound_id, double volume, double attenuation) { if (ent == NULL || ent->Sector->Flags & SECF_SILENT) return; @@ -1180,7 +1180,7 @@ void S_Sound (AActor *ent, int channel, FSoundID sound_id, float volume, float a // //========================================================================== -void S_Sound (const FPolyObj *poly, int channel, FSoundID sound_id, float volume, float attenuation) +void S_Sound (const FPolyObj *poly, int channel, FSoundID sound_id, double volume, double attenuation) { S_StartSound (NULL, NULL, poly, NULL, channel, sound_id, volume, attenuation); } @@ -1191,7 +1191,7 @@ void S_Sound (const FPolyObj *poly, int channel, FSoundID sound_id, float volume // //========================================================================== -void S_Sound (fixed_t x, fixed_t y, fixed_t z, int channel, FSoundID sound_id, float volume, float attenuation) +void S_Sound (fixed_t x, fixed_t y, fixed_t z, int channel, FSoundID sound_id, double volume, double attenuation) { FVector3 pt(FIXED2FLOAT(x), FIXED2FLOAT(z), FIXED2FLOAT(y)); S_StartSound (NULL, NULL, NULL, &pt, channel, sound_id, volume, attenuation); @@ -1203,7 +1203,7 @@ void S_Sound (fixed_t x, fixed_t y, fixed_t z, int channel, FSoundID sound_id, f // //========================================================================== -void S_Sound (const sector_t *sec, int channel, FSoundID sfxid, float volume, float attenuation) +void S_Sound (const sector_t *sec, int channel, FSoundID sfxid, double volume, double attenuation) { S_StartSound (NULL, sec, NULL, NULL, channel, sfxid, volume, attenuation); } diff --git a/src/s_sound.h b/src/s_sound.h index ad0f3c61b..78d450e20 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -217,11 +217,11 @@ void S_PrecacheLevel (); void S_CacheSound (sfxinfo_t *sfx); // Start sound for thing at <ent> -void S_Sound (int channel, FSoundID sfxid, float volume, float attenuation); -void S_Sound (AActor *ent, int channel, FSoundID sfxid, float volume, float attenuation); -void S_Sound (const FPolyObj *poly, int channel, FSoundID sfxid, float volume, float attenuation); -void S_Sound (const sector_t *sec, int channel, FSoundID sfxid, float volume, float attenuation); -void S_Sound (fixed_t x, fixed_t y, fixed_t z, int channel, FSoundID sfxid, float volume, float attenuation); +void S_Sound (int channel, FSoundID sfxid, double volume, double attenuation); +void S_Sound (AActor *ent, int channel, FSoundID sfxid, double volume, double attenuation); +void S_Sound (const FPolyObj *poly, int channel, FSoundID sfxid, double volume, double attenuation); +void S_Sound (const sector_t *sec, int channel, FSoundID sfxid, double volume, double attenuation); +void S_Sound (fixed_t x, fixed_t y, fixed_t z, int channel, FSoundID sfxid, double volume, double attenuation); // sound channels // channel 0 never willingly overrides diff --git a/src/sound/fmod_wrap.h b/src/sound/fmod_wrap.h index 3068c41d9..eae45c53b 100644 --- a/src/sound/fmod_wrap.h +++ b/src/sound/fmod_wrap.h @@ -47,7 +47,7 @@ namespace FMOD FMOD global system functions (optional). */ inline FMOD_RESULT Memory_Initialize(void *poolmem, int poollen, FMOD_MEMORY_ALLOCCALLBACK useralloc, FMOD_MEMORY_REALLOCCALLBACK userrealloc, FMOD_MEMORY_FREECALLBACK userfree, FMOD_MEMORY_TYPE memtypeflags = (FMOD_MEMORY_NORMAL | FMOD_MEMORY_XBOX360_PHYSICAL)) { return FMOD_Memory_Initialize(poolmem, poollen, useralloc, userrealloc, userfree, memtypeflags); } - inline FMOD_RESULT Memory_GetStats (int *currentalloced, int *maxalloced) { return FMOD_Memory_GetStats(currentalloced, maxalloced); } + //inline FMOD_RESULT Memory_GetStats (int *currentalloced, int *maxalloced) { return FMOD_Memory_GetStats(currentalloced, maxalloced); } inline FMOD_RESULT Debug_SetLevel(FMOD_DEBUGLEVEL level) { return FMOD_Debug_SetLevel(level); } inline FMOD_RESULT Debug_GetLevel(FMOD_DEBUGLEVEL *level) { return FMOD_Debug_GetLevel(level); } inline FMOD_RESULT File_SetDiskBusy(int busy) { return FMOD_File_SetDiskBusy(busy); } diff --git a/src/thingdef/olddecorations.cpp b/src/thingdef/olddecorations.cpp index 5948bc55d..5ab7a2674 100644 --- a/src/thingdef/olddecorations.cpp +++ b/src/thingdef/olddecorations.cpp @@ -234,24 +234,24 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) { if (extra.bExplosive) { - info->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_Explode")); + info->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_Explode")->Function); } } else { // The first frame plays the death sound and // the second frame makes it nonsolid. - info->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_Scream")); + info->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_Scream")->Function); if (extra.bSolidOnDeath) { } else if (extra.DeathStart + 1 < extra.DeathEnd) { - info->OwnedStates[extra.DeathStart+1].SetAction(FindGlobalActionFunction("A_NoBlocking")); + info->OwnedStates[extra.DeathStart+1].SetAction(FindGlobalActionFunction("A_NoBlocking")->Function); } else { - info->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_ScreamAndUnblock")); + info->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_ScreamAndUnblock")->Function); } if (extra.DeathHeight == 0) extra.DeathHeight = ((AActor*)(type->Defaults))->height; @@ -279,17 +279,17 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) // The first frame plays the burn sound and // the second frame makes it nonsolid. - info->OwnedStates[extra.FireDeathStart].SetAction(FindGlobalActionFunction("A_ActiveSound")); + info->OwnedStates[extra.FireDeathStart].SetAction(FindGlobalActionFunction("A_ActiveSound")->Function); if (extra.bSolidOnBurn) { } else if (extra.FireDeathStart + 1 < extra.FireDeathEnd) { - info->OwnedStates[extra.FireDeathStart+1].SetAction(FindGlobalActionFunction("A_NoBlocking")); + info->OwnedStates[extra.FireDeathStart+1].SetAction(FindGlobalActionFunction("A_NoBlocking")->Function); } else { - info->OwnedStates[extra.FireDeathStart].SetAction(FindGlobalActionFunction("A_ActiveAndUnblock")); + info->OwnedStates[extra.FireDeathStart].SetAction(FindGlobalActionFunction("A_ActiveAndUnblock")->Function); } if (extra.BurnHeight == 0) extra.BurnHeight = ((AActor*)(type->Defaults))->height; @@ -309,13 +309,13 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) info->OwnedStates[i].NextState = &info->OwnedStates[info->NumOwnedStates-1]; info->OwnedStates[i].Tics = 5; info->OwnedStates[i].Misc1 = 0; - info->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeath")); + info->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeath")->Function); i = info->NumOwnedStates - 1; info->OwnedStates[i].NextState = &info->OwnedStates[i]; info->OwnedStates[i].Tics = 1; info->OwnedStates[i].Misc1 = 0; - info->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeathChunks")); + info->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeathChunks")->Function); bag.statedef.SetStateLabel("Ice", &info->OwnedStates[extra.IceDeathStart]); } else if (extra.bGenericIceDeath) diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 605f161e5..4e526665d 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -302,9 +302,13 @@ static void FinishThingdef() p->Emit(&buildit); delete p; } - // FIXME: Call a real function buildit.Emit(OP_CALL_K, buildit.GetConstantAddress(NULL, ATAG_OBJECT), j, 0); VMScriptFunction *func = buildit.MakeFunction(); + func->NumArgs = tcall->Parameters.Size(); + for (int k = 0; k < tcall->NumStates; ++k) + { + tcall->ActorInfo->OwnedStates[tcall->FirstState + k].SetAction(func); + } #if 1 const char *marks = "======================================================="; char label[64]; @@ -318,10 +322,8 @@ static void FinishThingdef() fprintf(dump, "\nDisassembly:\n"); VMDisasm(dump, func->Code, func->CodeSize, func); #endif - //if(i==6) I_Error("Poop"); } fclose(dump); - I_Error("Poop"); for (i = 0; i < PClass::m_Types.Size(); i++) { diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index 43b78c4bd..60ff50620 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -187,6 +187,7 @@ struct AFuncDesc { const char *Name; actionf_p Function; + VMNativeFunction **VMPointer; }; AFuncDesc *FindFunction(const char * string); @@ -367,26 +368,27 @@ struct StateCallData // Macros to handle action functions. These are here so that I don't have to // change every single use in case the parameters change. -#define DECLARE_ACTION(name) void AF_##name(AActor *self, AActor *stateowner, FState *, int, StateCallData *); +#define DECLARE_ACTION(name) extern VMNativeFunction *name##_VMPtr; // This distinction is here so that CALL_ACTION produces errors when trying to // access a function that requires parameters. #define DEFINE_ACTION_FUNCTION(cls, name) \ - void AF_##name (AActor *self, AActor *stateowner, FState *, int, StateCallData *); \ - static AFuncDesc info_##cls##_##name = { #name, AF_##name }; \ - MSVC_ASEG AFuncDesc *infoptr_##cls##_##name GCC_ASEG = &info_##cls##_##name; \ - void AF_##name (AActor *self, AActor *stateowner, FState *, int, StateCallData *statecall) + static int AF_##name(VM_ARGS); \ + VMNativeFunction *name##_VMPtr; \ + static const AFuncDesc cls##_##name##_Hook = { #name, AF_##name, &name##_VMPtr }; \ + extern AFuncDesc const *const cls##_##name##_HookPtr; \ + MSVC_ASEG AFuncDesc const *const cls##_##name##_HookPtr GCC_ASEG = &cls##_##name##_Hook; \ + static int AF_##name(VM_ARGS) -#define DEFINE_ACTION_FUNCTION_PARAMS(cls, name) \ - void AFP_##name (AActor *self, AActor *stateowner, FState *CallingState, int ParameterIndex, StateCallData *statecall); \ - static AFuncDesc info_##cls##_##name = { #name, AFP_##name }; \ - MSVC_ASEG AFuncDesc *infoptr_##cls##_##name GCC_ASEG = &info_##cls##_##name; \ - void AFP_##name (AActor *self, AActor *stateowner, FState *CallingState, int ParameterIndex, StateCallData *statecall) +#define DEFINE_ACTION_FUNCTION_PARAMS(cls, name) DEFINE_ACTION_FUNCTION(cls, name) -#define DECLARE_PARAMINFO AActor *self, AActor *stateowner, FState *CallingState, int ParameterIndex, StateCallData *statecall -#define PUSH_PARAMINFO self, stateowner, CallingState, ParameterIndex, statecall +//#define DECLARE_PARAMINFO AActor *self, AActor *stateowner, FState *CallingState, int ParameterIndex, StateCallData *statecall +//#define PUSH_PARAMINFO self, stateowner, CallingState, ParameterIndex, statecall -#define CALL_ACTION(name,self) AF_##name(self, self, NULL, 0, NULL) +#define CALL_ACTION(name,self) { /*AF_##name(self, self, NULL, 0, NULL)*/ \ + VMValue params[5] = { self, self, NULL, VMValue(NULL, ATAG_STATE) }; \ + stack->Call(name##_VMPtr, params, countof(params), NULL, 0, NULL); \ + } int EvalExpressionI (DWORD x, AActor *self); @@ -398,6 +400,7 @@ FState *EvalExpressionState (DWORD x, AActor *self); const PClass *EvalExpressionClass (DWORD x, AActor *self); FName EvalExpressionName (DWORD x, AActor *self); +#if 0 #define ACTION_PARAM_START(count) #define ACTION_PARAM_INT(var, i) \ @@ -422,11 +425,12 @@ FName EvalExpressionName (DWORD x, AActor *self); FName var = EvalExpressionName(ParameterIndex+i, self); #define ACTION_PARAM_ANGLE(var,i) \ angle_t var = angle_t(EvalExpressionF(ParameterIndex+i, self)*ANGLE_90/90.f); +#endif #define ACTION_SET_RESULT(v) if (statecall != NULL) statecall->Result = v; // Checks to see what called the current action function -#define ACTION_CALL_FROM_ACTOR() (CallingState == self->state) -#define ACTION_CALL_FROM_WEAPON() (self->player && CallingState != self->state && statecall == NULL) +#define ACTION_CALL_FROM_ACTOR() (callingstate == self->state) +#define ACTION_CALL_FROM_WEAPON() (self->player && callingstate != self->state && statecall == NULL) #define ACTION_CALL_FROM_INVENTORY() (statecall != NULL) #endif diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 39a08cacd..9da7ff3b5 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -142,22 +142,30 @@ bool ACustomInventory::CallStateChain (AActor *actor, FState * State) //========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_SetSolid) { + PARAM_ACTION_PROLOGUE; self->flags |= MF_SOLID; + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_UnsetSolid) { + PARAM_ACTION_PROLOGUE; self->flags &= ~MF_SOLID; + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_SetFloat) { + PARAM_ACTION_PROLOGUE; self->flags |= MF_FLOAT; + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_UnsetFloat) { + PARAM_ACTION_PROLOGUE; self->flags &= ~(MF_FLOAT|MF_INFLOAT); + return 0; } //========================================================================== @@ -204,37 +212,46 @@ static void DoAttack (AActor *self, bool domelee, bool domissile, DEFINE_ACTION_FUNCTION(AActor, A_MeleeAttack) { - int MeleeDamage = self->GetClass()->Meta.GetMetaInt (ACMETA_MeleeDamage, 0); - FSoundID MeleeSound = self->GetClass()->Meta.GetMetaInt (ACMETA_MeleeSound, 0); + PARAM_ACTION_PROLOGUE; + int MeleeDamage = self->GetClass()->Meta.GetMetaInt(ACMETA_MeleeDamage, 0); + FSoundID MeleeSound = self->GetClass()->Meta.GetMetaInt(ACMETA_MeleeSound, 0); DoAttack(self, true, false, MeleeDamage, MeleeSound, NULL, 0); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_MissileAttack) { - const PClass *MissileType=PClass::FindClass((ENamedName) self->GetClass()->Meta.GetMetaInt (ACMETA_MissileName, NAME_None)); - fixed_t MissileHeight= self->GetClass()->Meta.GetMetaFixed (ACMETA_MissileHeight, 32*FRACUNIT); + PARAM_ACTION_PROLOGUE; + const PClass *MissileType = PClass::FindClass(ENamedName(self->GetClass()->Meta.GetMetaInt(ACMETA_MissileName, NAME_None))); + fixed_t MissileHeight = self->GetClass()->Meta.GetMetaFixed(ACMETA_MissileHeight, 32*FRACUNIT); DoAttack(self, false, true, 0, 0, MissileType, MissileHeight); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_ComboAttack) { - int MeleeDamage = self->GetClass()->Meta.GetMetaInt (ACMETA_MeleeDamage, 0); - FSoundID MeleeSound = self->GetClass()->Meta.GetMetaInt (ACMETA_MeleeSound, 0); - const PClass *MissileType=PClass::FindClass((ENamedName) self->GetClass()->Meta.GetMetaInt (ACMETA_MissileName, NAME_None)); - fixed_t MissileHeight= self->GetClass()->Meta.GetMetaFixed (ACMETA_MissileHeight, 32*FRACUNIT); + PARAM_ACTION_PROLOGUE; + int MeleeDamage = self->GetClass()->Meta.GetMetaInt(ACMETA_MeleeDamage, 0); + FSoundID MeleeSound = self->GetClass()->Meta.GetMetaInt(ACMETA_MeleeSound, 0); + const PClass *MissileType = PClass::FindClass(ENamedName(self->GetClass()->Meta.GetMetaInt(ACMETA_MissileName, NAME_None))); + fixed_t MissileHeight = self->GetClass()->Meta.GetMetaFixed(ACMETA_MissileHeight, 32*FRACUNIT); DoAttack(self, true, true, MeleeDamage, MeleeSound, MissileType, MissileHeight); + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BasicAttack) { - ACTION_PARAM_START(4); - ACTION_PARAM_INT(MeleeDamage, 0); - ACTION_PARAM_SOUND(MeleeSound, 1); - ACTION_PARAM_CLASS(MissileType, 2); - ACTION_PARAM_FIXED(MissileHeight, 3); + PARAM_ACTION_PROLOGUE; + PARAM_INT (melee_damage); + PARAM_SOUND (melee_sound); + PARAM_CLASS (missile_type, AActor); + PARAM_FIXED (missile_height); - if (MissileType == NULL) return; - DoAttack(self, true, true, MeleeDamage, MeleeSound, MissileType, MissileHeight); + if (missile_type != NULL) + { + DoAttack(self, true, true, melee_damage, melee_sound, missile_type, missile_height); + } + return 0; } //========================================================================== @@ -245,12 +262,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BasicAttack) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlaySound) { - ACTION_PARAM_START(5); - ACTION_PARAM_SOUND(soundid, 0); - ACTION_PARAM_INT(channel, 1); - ACTION_PARAM_FLOAT(volume, 2); - ACTION_PARAM_BOOL(looping, 3); - ACTION_PARAM_FLOAT(attenuation, 4); + PARAM_ACTION_PROLOGUE; + PARAM_SOUND_OPT (soundid) { soundid = "weapons/pistol"; } + PARAM_INT_OPT (channel) { channel = CHAN_BODY; } + PARAM_FLOAT_OPT (volume) { volume = 1; } + PARAM_BOOL_OPT (looping) { looping = false; } + PARAM_FLOAT_OPT (attenuation) { attenuation = ATTN_NORM; } if (!looping) { @@ -263,14 +280,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlaySound) S_Sound (self, channel | CHAN_LOOP, soundid, volume, attenuation); } } + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StopSound) { - ACTION_PARAM_START(1); - ACTION_PARAM_INT(slot, 0); + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT(slot) { slot = CHAN_VOICE; } S_StopSound(self, slot); + return 0; } //========================================================================== @@ -284,19 +303,20 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StopSound) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlayWeaponSound) { - ACTION_PARAM_START(1); - ACTION_PARAM_SOUND(soundid, 0); + PARAM_ACTION_PROLOGUE; + PARAM_SOUND(soundid); - S_Sound (self, CHAN_WEAPON, soundid, 1, ATTN_NORM); + S_Sound(self, CHAN_WEAPON, soundid, 1, ATTN_NORM); + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlaySoundEx) { - ACTION_PARAM_START(4); - ACTION_PARAM_SOUND(soundid, 0); - ACTION_PARAM_NAME(channel, 1); - ACTION_PARAM_BOOL(looping, 2); - ACTION_PARAM_INT(attenuation_raw, 3); + PARAM_ACTION_PROLOGUE; + PARAM_SOUND (soundid); + PARAM_NAME (channel); + PARAM_BOOL_OPT (looping) { looping = false; } + PARAM_INT_OPT (attenuation_raw) { attenuation_raw = 0; } float attenuation; switch (attenuation_raw) @@ -324,17 +344,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlaySoundEx) S_Sound (self, (int(channel) - NAME_Auto) | CHAN_LOOP, soundid, 1, attenuation); } } + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StopSoundEx) { - ACTION_PARAM_START(1); - ACTION_PARAM_NAME(channel, 0); + PARAM_ACTION_PROLOGUE; + PARAM_NAME(channel); if (channel > NAME_Auto && channel <= NAME_SoundSlot7) { S_StopSound (self, int(channel) - NAME_Auto); } + return 0; } //========================================================================== @@ -344,11 +366,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StopSoundEx) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SeekerMissile) { - ACTION_PARAM_START(2); - ACTION_PARAM_INT(ang1, 0); - ACTION_PARAM_INT(ang2, 1); + PARAM_ACTION_PROLOGUE; + PARAM_INT(ang1); + PARAM_INT(ang2); P_SeekerMissile(self, clamp<int>(ang1, 0, 90) * ANGLE_1, clamp<int>(ang2, 0, 90) * ANGLE_1); + return 0; } //========================================================================== @@ -358,11 +381,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SeekerMissile) //========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_BulletAttack) { + PARAM_ACTION_PROLOGUE; + int i; int bangle; int slope; - if (!self->target) return; + if (!self->target) return 0; A_FaceTarget (self); bangle = self->angle; @@ -377,6 +402,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BulletAttack) P_LineAttack(self, angle, MISSILERANGE, slope, damage, NAME_None, NAME_BulletPuff); } + return 0; } @@ -385,7 +411,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BulletAttack) // Do the state jump // //========================================================================== -static void DoJump(AActor * self, FState * CallingState, FState *jumpto, StateCallData *statecall) +static void DoJump(AActor *self, FState *callingstate, FState *jumpto, StateCallData *statecall) { if (jumpto == NULL) return; @@ -393,17 +419,17 @@ static void DoJump(AActor * self, FState * CallingState, FState *jumpto, StateCa { statecall->State = jumpto; } - else if (self->player != NULL && CallingState == self->player->psprites[ps_weapon].state) + else if (self->player != NULL && callingstate == self->player->psprites[ps_weapon].state) { P_SetPsprite(self->player, ps_weapon, jumpto); } - else if (self->player != NULL && CallingState == self->player->psprites[ps_flash].state) + else if (self->player != NULL && callingstate == self->player->psprites[ps_flash].state) { P_SetPsprite(self->player, ps_flash, jumpto); } - else if (CallingState == self->state) + else if (callingstate == self->state) { - self->SetState (jumpto); + self->SetState(jumpto); } else { @@ -414,7 +440,7 @@ static void DoJump(AActor * self, FState * CallingState, FState *jumpto, StateCa // This is just to avoid having to directly reference the internally defined // CallingState and statecall parameters in the code below. -#define ACTION_JUMP(offset) DoJump(self, CallingState, offset, statecall) +#define ACTION_JUMP(offset) DoJump(self, callingstate, offset, statecall) //========================================================================== // @@ -423,17 +449,18 @@ static void DoJump(AActor * self, FState * CallingState, FState *jumpto, StateCa //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Jump) { - ACTION_PARAM_START(3); - ACTION_PARAM_INT(count, 0); - ACTION_PARAM_INT(maxchance, 1); + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT(maxchance) { maxchance = 256; } - if (count >= 2 && (maxchance >= 256 || pr_cajump() < maxchance)) + int count = numparam - pnum; + if (count > 0 && (maxchance >= 256 || pr_cajump() < maxchance)) { - int jumps = 2 + (count == 2? 0 : (pr_cajump() % (count - 1))); - ACTION_PARAM_STATE(jumpto, jumps); + int jumpnum = (count == 1 ? 0 : (pr_cajump() % count)); + PARAM_STATE_AT(pnum + jumpnum, jumpto); ACTION_JUMP(jumpto); } ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! + return 0; } //========================================================================== @@ -443,13 +470,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Jump) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfHealthLower) { - ACTION_PARAM_START(2); - ACTION_PARAM_INT(health, 0); - ACTION_PARAM_STATE(jump, 1); - - if (self->health < health) ACTION_JUMP(jump); + PARAM_ACTION_PROLOGUE; + PARAM_INT (health); + PARAM_STATE (jump); + if (self->health < health) + { + ACTION_JUMP(jump); + } ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! + return 0; } //========================================================================== @@ -459,15 +489,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfHealthLower) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfCloser) { - ACTION_PARAM_START(2); - ACTION_PARAM_FIXED(dist, 0); - ACTION_PARAM_STATE(jump, 1); + PARAM_ACTION_PROLOGUE; + PARAM_FIXED (dist); + PARAM_STATE (jump); AActor *target; - if (!self->player) + if (self->player == NULL) { - target=self->target; + target = self->target; } else { @@ -478,7 +508,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfCloser) ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! // No target - no jump - if (target==NULL) return; + if (target == NULL) + return 0; if (P_AproxDistance(self->x-target->x, self->y-target->y) < dist && ( (self->z > target->z && self->z - (target->z + target->height) < dist) || @@ -488,6 +519,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfCloser) { ACTION_JUMP(jump); } + return 0; } //========================================================================== @@ -495,41 +527,46 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfCloser) // State jump function // //========================================================================== -void DoJumpIfInventory(AActor * owner, DECLARE_PARAMINFO) +void DoJumpIfInventory(AActor *owner, AActor *self, StateCallData *statecall, FState *callingstate, VMValue *param, int numparam) { - ACTION_PARAM_START(3); - ACTION_PARAM_CLASS(Type, 0); - ACTION_PARAM_INT(ItemAmount, 1); - ACTION_PARAM_STATE(JumpOffset, 2); + int pnum = NAP; + PARAM_CLASS (itemtype, AInventory); + PARAM_INT (itemamount); + PARAM_STATE (label); ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - if (!Type || owner == NULL) return; + if (itemtype == NULL || owner == NULL) + return; - AInventory *Item = owner->FindInventory(Type); + AInventory *item = owner->FindInventory(itemtype); - if (Item) + if (item) { - if (ItemAmount > 0) + if (itemamount > 0) { - if (Item->Amount >= ItemAmount) - ACTION_JUMP(JumpOffset); + if (item->Amount >= itemamount) + ACTION_JUMP(label); } - else if (Item->Amount >= Item->MaxAmount) + else if (item->Amount >= item->MaxAmount) { - ACTION_JUMP(JumpOffset); + ACTION_JUMP(label); } } } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInventory) { - DoJumpIfInventory(self, PUSH_PARAMINFO); + PARAM_ACTION_PROLOGUE; + DoJumpIfInventory(self, self, statecall, callingstate, param, numparam); + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetInventory) { - DoJumpIfInventory(self->target, PUSH_PARAMINFO); + PARAM_ACTION_PROLOGUE; + DoJumpIfInventory(self->target, self, statecall, callingstate, param, numparam); + return 0; } //========================================================================== @@ -539,17 +576,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetInventory) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfArmorType) { - ACTION_PARAM_START(3); - ACTION_PARAM_NAME(Type, 0); - ACTION_PARAM_STATE(JumpOffset, 1); - ACTION_PARAM_INT(amount, 2); + PARAM_ACTION_PROLOGUE; + PARAM_NAME (type); + PARAM_STATE (label); + PARAM_INT_OPT(amount) { amount = 1; } ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - ABasicArmor * armor = (ABasicArmor *) self->FindInventory(NAME_BasicArmor); + ABasicArmor *armor = (ABasicArmor *)self->FindInventory(NAME_BasicArmor); - if (armor && armor->ArmorType == Type && armor->Amount >= amount) - ACTION_JUMP(JumpOffset); + if (armor && armor->ArmorType == type && armor->Amount >= amount) + ACTION_JUMP(label); + return 0; } //========================================================================== @@ -560,14 +598,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfArmorType) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode) { - ACTION_PARAM_START(7); - ACTION_PARAM_INT(damage, 0); - ACTION_PARAM_INT(distance, 1); - ACTION_PARAM_BOOL(hurtSource, 2); - ACTION_PARAM_BOOL(alert, 3); - ACTION_PARAM_INT(fulldmgdistance, 4); - ACTION_PARAM_INT(nails, 5); - ACTION_PARAM_INT(naildamage, 6); + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT (damage) { damage = -1; } + PARAM_INT_OPT (distance) { distance = -1; } + PARAM_BOOL_OPT (hurtSource) { hurtSource = true; } + PARAM_BOOL_OPT (alert) { alert = false; } + PARAM_INT_OPT (fulldmgdistance) { fulldmgdistance = 0; } + PARAM_INT_OPT (nails) { nails = 0; } + PARAM_INT_OPT (naildamage) { naildamage = 10; } if (damage < 0) // get parameters from metadata { @@ -606,6 +644,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode) validcount++; P_RecursiveSound (self->Sector, self->target, false, 0); } + return 0; } //========================================================================== @@ -616,19 +655,20 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusThrust) { - ACTION_PARAM_START(3); - ACTION_PARAM_INT(force, 0); - ACTION_PARAM_FIXED(distance, 1); - ACTION_PARAM_BOOL(affectSource, 2); + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT (force) { force = 128; } + PARAM_INT_OPT (distance) { distance = 1; } + PARAM_BOOL_OPT (affectSource) { affectSource = true; } if (force <= 0) force = 128; if (distance <= 0) distance = force; P_RadiusAttack (self, self->target, force, distance, self->DamageType, affectSource, false); - if (self->z <= self->floorz + (distance<<FRACBITS)) + if (self->z <= self->floorz + (distance << FRACBITS)) { P_HitFloor (self); } + return 0; } //========================================================================== @@ -638,17 +678,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusThrust) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CallSpecial) { - ACTION_PARAM_START(6); - ACTION_PARAM_INT(special, 0); - ACTION_PARAM_INT(arg1, 1); - ACTION_PARAM_INT(arg2, 2); - ACTION_PARAM_INT(arg3, 3); - ACTION_PARAM_INT(arg4, 4); - ACTION_PARAM_INT(arg5, 5); + PARAM_ACTION_PROLOGUE; + PARAM_INT (special); + PARAM_INT_OPT (arg1) { arg1 = 0; } + PARAM_INT_OPT (arg2) { arg2 = 0; } + PARAM_INT_OPT (arg3) { arg3 = 0; } + PARAM_INT_OPT (arg4) { arg4 = 0; } + PARAM_INT_OPT (arg5) { arg5 = 0; } bool res = !!LineSpecials[special](NULL, self, false, arg1, arg2, arg3, arg4, arg5); ACTION_SET_RESULT(res); + return 0; } //========================================================================== @@ -659,9 +700,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CallSpecial) // with an optional flag // //========================================================================== -inline static bool isMissile(AActor * self, bool precise=true) +inline static bool isMissile(AActor *self, bool precise=true) { - return self->flags&MF_MISSILE || (precise && self->GetDefault()->flags&MF_MISSILE); + return (self->flags & MF_MISSILE) || (precise && (self->GetDefault()->flags & MF_MISSILE)); } //========================================================================== @@ -678,107 +719,108 @@ enum CM_Flags DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile) { - ACTION_PARAM_START(6); - ACTION_PARAM_CLASS(ti, 0); - ACTION_PARAM_FIXED(SpawnHeight, 1); - ACTION_PARAM_INT(Spawnofs_XY, 2); - ACTION_PARAM_ANGLE(Angle, 3); - ACTION_PARAM_INT(flags, 4); - ACTION_PARAM_ANGLE(pitch, 5); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS (ti, AActor); + PARAM_FIXED_OPT (spawnheight) { spawnheight = 32*FRACUNIT; } + PARAM_INT_OPT (spawnofs_xy) { spawnofs_xy = 0; } + PARAM_ANGLE_OPT (angle) { angle = 0; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_INT_OPT (pitch) { pitch = 0; } int aimmode = flags & CMF_AIMMODE; AActor * targ; AActor * missile; - if (self->target != NULL || aimmode==2) + if (self->target != NULL || aimmode == 2) { if (ti) { angle_t ang = (self->angle - ANGLE_90) >> ANGLETOFINESHIFT; - fixed_t x = Spawnofs_XY * finecosine[ang]; - fixed_t y = Spawnofs_XY * finesine[ang]; - fixed_t z = SpawnHeight - 32*FRACUNIT + (self->player? self->player->crouchoffset : 0); + fixed_t x = spawnofs_xy * finecosine[ang]; + fixed_t y = spawnofs_xy * finesine[ang]; + fixed_t z = spawnheight - 32*FRACUNIT + (self->player? self->player->crouchoffset : 0); switch (aimmode) { case 0: default: // same adjustment as above (in all 3 directions this time) - for better aiming! - self->x+=x; - self->y+=y; - self->z+=z; + self->x += x; + self->y += y; + self->z += z; missile = P_SpawnMissileXYZ(self->x, self->y, self->z + 32*FRACUNIT, self, self->target, ti, false); - self->x-=x; - self->y-=y; - self->z-=z; + self->x -= x; + self->y -= y; + self->z -= z; break; case 1: - missile = P_SpawnMissileXYZ(self->x+x, self->y+y, self->z+SpawnHeight, self, self->target, ti, false); + missile = P_SpawnMissileXYZ(self->x+x, self->y+y, self->z+spawnheight, self, self->target, ti, false); break; case 2: - self->x+=x; - self->y+=y; - missile = P_SpawnMissileAngleZSpeed(self, self->z+SpawnHeight, ti, self->angle, 0, GetDefaultByType(ti)->Speed, self, false); - self->x-=x; - self->y-=y; + self->x += x; + self->y += y; + missile = P_SpawnMissileAngleZSpeed(self, self->z+spawnheight, ti, self->angle, 0, GetDefaultByType(ti)->Speed, self, false); + self->x -= x; + self->y -= y; // It is not necessary to use the correct angle here. // The only important thing is that the horizontal velocity is correct. // Therefore use 0 as the missile's angle and simplify the calculations accordingly. // The actual velocity vector is set below. - if (missile) + if (missile != NULL) { fixed_t vx = finecosine[pitch>>ANGLETOFINESHIFT]; fixed_t vz = finesine[pitch>>ANGLETOFINESHIFT]; - missile->velx = FixedMul (vx, missile->Speed); + missile->velx = FixedMul(vx, missile->Speed); missile->vely = 0; - missile->velz = FixedMul (vz, missile->Speed); + missile->velz = FixedMul(vz, missile->Speed); } break; } - if (missile) + if (missile != NULL) { // Use the actual velocity instead of the missile's Speed property // so that this can handle missiles with a high vertical velocity // component properly. - FVector3 velocity (missile->velx, missile->vely, 0); + FVector2 velocity (missile->velx, missile->vely); fixed_t missilespeed = (fixed_t)velocity.Length(); - missile->angle += Angle; + missile->angle += angle; ang = missile->angle >> ANGLETOFINESHIFT; - missile->velx = FixedMul (missilespeed, finecosine[ang]); - missile->vely = FixedMul (missilespeed, finesine[ang]); + missile->velx = FixedMul(missilespeed, finecosine[ang]); + missile->vely = FixedMul(missilespeed, finesine[ang]); // handle projectile shooting projectiles - track the // links back to a real owner if (isMissile(self, !!(flags & CMF_TRACKOWNER))) { - AActor * owner=self ;//->target; - while (isMissile(owner, !!(flags & CMF_TRACKOWNER)) && owner->target) owner=owner->target; - targ=owner; - missile->target=owner; + AActor *owner = self;//->target; + while (isMissile(owner, !!(flags & CMF_TRACKOWNER)) && owner->target) + owner = owner->target; + targ = owner; + missile->target = owner; // automatic handling of seeker missiles if (self->flags & missile->flags2 & MF2_SEEKERMISSILE) { - missile->tracer=self->tracer; + missile->tracer = self->tracer; } } - else if (missile->flags2&MF2_SEEKERMISSILE) + else if (missile->flags2 & MF2_SEEKERMISSILE) { // automatic handling of seeker missiles - missile->tracer=self->target; + missile->tracer = self->target; } // set the health value so that the missile works properly - if (missile->flags4&MF4_SPECTRAL) + if (missile->flags4 & MF4_SPECTRAL) { - missile->health=-2; + missile->health = -2; } P_CheckMissileSpawn(missile); } @@ -787,8 +829,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile) else if (flags & CMF_CHECKTARGETDEAD) { // Target is dead and the attack shall be aborted. - if (self->SeeState != NULL) self->SetState(self->SeeState); + if (self->SeeState != NULL) + self->SetState(self->SeeState); } + return 0; } //========================================================================== @@ -798,39 +842,39 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) { - ACTION_PARAM_START(7); - ACTION_PARAM_ANGLE(Spread_XY, 0); - ACTION_PARAM_ANGLE(Spread_Z, 1); - ACTION_PARAM_INT(NumBullets, 2); - ACTION_PARAM_INT(DamagePerBullet, 3); - ACTION_PARAM_CLASS(pufftype, 4); - ACTION_PARAM_FIXED(Range, 5); - ACTION_PARAM_BOOL(AimFacing, 6); + PARAM_ACTION_PROLOGUE; + PARAM_ANGLE (spread_xy); + PARAM_ANGLE (spread_z); + PARAM_INT (numbullets); + PARAM_INT (damageperbullet); + PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindClass(NAME_BulletPuff); } + PARAM_FIXED_OPT (range) { range = MISSILERANGE; } + PARAM_BOOL_OPT (aimfacing) { aimfacing = false; } - if(Range==0) Range=MISSILERANGE; + if (range == 0) + range = MISSILERANGE; int i; int bangle; int bslope; - if (self->target || AimFacing) + if (self->target || aimfacing) { - if (!AimFacing) A_FaceTarget (self); + if (!aimfacing) A_FaceTarget (self); bangle = self->angle; - if (!pufftype) pufftype = PClass::FindClass(NAME_BulletPuff); - bslope = P_AimLineAttack (self, bangle, MISSILERANGE); S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); - for (i=0 ; i<NumBullets ; i++) + for (i = 0; i < numbullets; i++) { - int angle = bangle + pr_cabullet.Random2() * (Spread_XY / 255); - int slope = bslope + pr_cabullet.Random2() * (Spread_Z / 255); - int damage = ((pr_cabullet()%3)+1) * DamagePerBullet; - P_LineAttack(self, angle, Range, slope, damage, GetDefaultByType(pufftype)->DamageType, pufftype); + int angle = bangle + pr_cabullet.Random2() * (spread_xy / 255); + int slope = bslope + pr_cabullet.Random2() * (spread_z / 255); + int damage = ((pr_cabullet()%3)+1) * damageperbullet; + P_LineAttack(self, angle, range, slope, damage, GetDefaultByType(pufftype)->DamageType, pufftype); } } + return 0; } //========================================================================== @@ -840,29 +884,34 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMeleeAttack) { - ACTION_PARAM_START(5); - ACTION_PARAM_INT(damage, 0); - ACTION_PARAM_SOUND(MeleeSound, 1); - ACTION_PARAM_SOUND(MissSound, 2); - ACTION_PARAM_NAME(DamageType, 3); - ACTION_PARAM_BOOL(bleed, 4); + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT (damage) { damage = 0; } + PARAM_SOUND_OPT (meleesound) { meleesound = 0; } + PARAM_SOUND_OPT (misssound) { misssound = 0; } + PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } + PARAM_BOOL_OPT (bleed) { bleed = true; } - if (DamageType==NAME_None) DamageType = NAME_Melee; // Melee is the default type + if (damagetype == NAME_None) + damagetype = NAME_Melee; // Melee is the default type if (!self->target) - return; + return 0; A_FaceTarget (self); if (self->CheckMeleeRange ()) { - if (MeleeSound) S_Sound (self, CHAN_WEAPON, MeleeSound, 1, ATTN_NORM); - P_DamageMobj (self->target, self, self, damage, DamageType); - if (bleed) P_TraceBleed (damage, self->target, self); + if (meleesound) + S_Sound (self, CHAN_WEAPON, meleesound, 1, ATTN_NORM); + P_DamageMobj (self->target, self, self, damage, damagetype); + if (bleed) + P_TraceBleed (damage, self->target, self); } else { - if (MissSound) S_Sound (self, CHAN_WEAPON, MissSound, 1, ATTN_NORM); + if (misssound) + S_Sound (self, CHAN_WEAPON, misssound, 1, ATTN_NORM); } + return 0; } //========================================================================== @@ -872,47 +921,51 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMeleeAttack) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomComboAttack) { - ACTION_PARAM_START(6); - ACTION_PARAM_CLASS(ti, 0); - ACTION_PARAM_FIXED(SpawnHeight, 1); - ACTION_PARAM_INT(damage, 2); - ACTION_PARAM_SOUND(MeleeSound, 3); - ACTION_PARAM_NAME(DamageType, 4); - ACTION_PARAM_BOOL(bleed, 5); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS (ti, AActor); + PARAM_FIXED (spawnheight); + PARAM_INT (damage); + PARAM_SOUND_OPT (meleesound) { meleesound = 0; } + PARAM_NAME_OPT (damagetype) { damagetype = NAME_Melee; } + PARAM_BOOL_OPT (bleed) { bleed = true; } if (!self->target) - return; + return 0; A_FaceTarget (self); - if (self->CheckMeleeRange ()) + if (self->CheckMeleeRange()) { - if (DamageType==NAME_None) DamageType = NAME_Melee; // Melee is the default type - if (MeleeSound) S_Sound (self, CHAN_WEAPON, MeleeSound, 1, ATTN_NORM); - P_DamageMobj (self->target, self, self, damage, DamageType); - if (bleed) P_TraceBleed (damage, self->target, self); + if (damagetype == NAME_None) + damagetype = NAME_Melee; // Melee is the default type + if (meleesound) + S_Sound (self, CHAN_WEAPON, meleesound, 1, ATTN_NORM); + P_DamageMobj (self->target, self, self, damage, damagetype); + if (bleed) + P_TraceBleed (damage, self->target, self); } else if (ti) { // This seemingly senseless code is needed for proper aiming. - self->z+=SpawnHeight-32*FRACUNIT; - AActor * missile = P_SpawnMissileXYZ (self->x, self->y, self->z + 32*FRACUNIT, self, self->target, ti, false); - self->z-=SpawnHeight-32*FRACUNIT; + self->z += spawnheight - 32*FRACUNIT; + AActor *missile = P_SpawnMissileXYZ(self->x, self->y, self->z + 32*FRACUNIT, self, self->target, ti, false); + self->z -= spawnheight - 32*FRACUNIT; if (missile) { // automatic handling of seeker missiles - if (missile->flags2&MF2_SEEKERMISSILE) + if (missile->flags2 & MF2_SEEKERMISSILE) { - missile->tracer=self->target; + missile->tracer = self->target; } // set the health value so that the missile works properly - if (missile->flags4&MF4_SPECTRAL) + if (missile->flags4 & MF4_SPECTRAL) { - missile->health=-2; + missile->health = -2; } P_CheckMissileSpawn(missile); } } + return 0; } //========================================================================== @@ -922,17 +975,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomComboAttack) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfNoAmmo) { - ACTION_PARAM_START(1); - ACTION_PARAM_STATE(jump, 0); + PARAM_ACTION_PROLOGUE; + PARAM_STATE(jump); ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - if (!ACTION_CALL_FROM_WEAPON()) return; + if (!ACTION_CALL_FROM_WEAPON()) + return 0; if (!self->player->ReadyWeapon->CheckAmmo(self->player->ReadyWeapon->bAltFire, false, true)) { ACTION_JUMP(jump); } - + return 0; } @@ -943,56 +997,61 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfNoAmmo) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets) { - ACTION_PARAM_START(7); - ACTION_PARAM_ANGLE(Spread_XY, 0); - ACTION_PARAM_ANGLE(Spread_Z, 1); - ACTION_PARAM_INT(NumberOfBullets, 2); - ACTION_PARAM_INT(DamagePerBullet, 3); - ACTION_PARAM_CLASS(PuffType, 4); - ACTION_PARAM_BOOL(UseAmmo, 5); - ACTION_PARAM_FIXED(Range, 6); + PARAM_ACTION_PROLOGUE; + PARAM_ANGLE (spread_xy); + PARAM_ANGLE (spread_z); + PARAM_INT (numbullets); + PARAM_INT (damageperbullet); + PARAM_CLASS_OPT (pufftype, AActor) { pufftype = NULL; } + PARAM_BOOL_OPT (useammo) { useammo = true; } + PARAM_FIXED_OPT (range) { range = 0; } - if (!self->player) return; + if (!self->player) return 0; - player_t * player=self->player; - AWeapon * weapon=player->ReadyWeapon; + player_t *player = self->player; + AWeapon *weapon = player->ReadyWeapon; int i; int bangle; int bslope; - if (UseAmmo && weapon) + if (useammo && weapon) { - if (!weapon->DepleteAmmo(weapon->bAltFire, true)) return; // out of ammo + if (!weapon->DepleteAmmo(weapon->bAltFire, true)) + return 0; // out of ammo } - if (Range == 0) Range = PLAYERMISSILERANGE; + if (range == 0) + range = PLAYERMISSILERANGE; - static_cast<APlayerPawn *>(self)->PlayAttacking2 (); + static_cast<APlayerPawn *>(self)->PlayAttacking2(); bslope = P_BulletSlope(self); bangle = self->angle; - if (!PuffType) PuffType = PClass::FindClass(NAME_BulletPuff); + if (pufftype == NULL) + pufftype = PClass::FindClass(NAME_BulletPuff); - S_Sound (self, CHAN_WEAPON, weapon->AttackSound, 1, ATTN_NORM); + S_Sound(self, CHAN_WEAPON, weapon->AttackSound, 1, ATTN_NORM); - if ((NumberOfBullets==1 && !player->refire) || NumberOfBullets==0) + if ((numbullets == 1 && !player->refire) || numbullets == 0) { - int damage = ((pr_cwbullet()%3)+1)*DamagePerBullet; - P_LineAttack(self, bangle, Range, bslope, damage, GetDefaultByType(PuffType)->DamageType, PuffType); + int damage = ((pr_cwbullet()%3)+1) * damageperbullet; + P_LineAttack(self, bangle, range, bslope, damage, GetDefaultByType(pufftype)->DamageType, pufftype); } else { - if (NumberOfBullets == -1) NumberOfBullets = 1; - for (i=0 ; i<NumberOfBullets ; i++) + if (numbullets < 0) + numbullets = 1; + for (i = 0; i < numbullets; i++) { - int angle = bangle + pr_cwbullet.Random2() * (Spread_XY / 255); - int slope = bslope + pr_cwbullet.Random2() * (Spread_Z / 255); - int damage = ((pr_cwbullet()%3)+1) * DamagePerBullet; - P_LineAttack(self, angle, Range, slope, damage, GetDefaultByType(PuffType)->DamageType, PuffType); + int angle = bangle + pr_cwbullet.Random2() * (spread_xy / 255); + int slope = bslope + pr_cwbullet.Random2() * (spread_z / 255); + int damage = ((pr_cwbullet()%3)+1) * damageperbullet; + P_LineAttack(self, angle, range, slope, damage, GetDefaultByType(pufftype)->DamageType, pufftype); } } + return 0; } @@ -1003,58 +1062,62 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireCustomMissile) { - ACTION_PARAM_START(7); - ACTION_PARAM_CLASS(ti, 0); - ACTION_PARAM_ANGLE(Angle, 1); - ACTION_PARAM_BOOL(UseAmmo, 2); - ACTION_PARAM_INT(SpawnOfs_XY, 3); - ACTION_PARAM_FIXED(SpawnHeight, 4); - ACTION_PARAM_BOOL(AimAtAngle, 5); - ACTION_PARAM_ANGLE(pitch, 6); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS (ti, AActor); + PARAM_ANGLE_OPT (angle) { angle = 0; } + PARAM_BOOL_OPT (useammo) { useammo = true; } + PARAM_INT_OPT (spawnofs_xy) { spawnofs_xy = 0; } + PARAM_FIXED_OPT (spawnheight) { spawnheight = 0; } + PARAM_BOOL_OPT (aimatangle) { aimatangle = false; } + PARAM_ANGLE_OPT (pitch) { pitch = 0; } - if (!self->player) return; + if (!self->player) + return 0; - player_t *player=self->player; - AWeapon * weapon=player->ReadyWeapon; + player_t *player = self->player; + AWeapon *weapon = player->ReadyWeapon; AActor *linetarget; - if (UseAmmo && weapon) + if (useammo && weapon) { - if (!weapon->DepleteAmmo(weapon->bAltFire, true)) return; // out of ammo + if (!weapon->DepleteAmmo(weapon->bAltFire, true)) + return 0; // out of ammo } if (ti) { angle_t ang = (self->angle - ANGLE_90) >> ANGLETOFINESHIFT; - fixed_t x = SpawnOfs_XY * finecosine[ang]; - fixed_t y = SpawnOfs_XY * finesine[ang]; - fixed_t z = SpawnHeight; + fixed_t x = spawnofs_xy * finecosine[ang]; + fixed_t y = spawnofs_xy * finesine[ang]; + fixed_t z = spawnheight; fixed_t shootangle = self->angle; - if (AimAtAngle) shootangle+=Angle; + if (aimatangle) shootangle += angle; // Temporarily adjusts the pitch - fixed_t SavedPlayerPitch = self->pitch; + fixed_t saved_player_pitch = self->pitch; self->pitch -= pitch; - AActor * misl=P_SpawnPlayerMissile (self, x, y, z, ti, shootangle, &linetarget); - self->pitch = SavedPlayerPitch; + AActor *misl = P_SpawnPlayerMissile (self, x, y, z, ti, shootangle, &linetarget); + self->pitch = saved_player_pitch; // automatic handling of seeker missiles if (misl) { - if (linetarget && misl->flags2&MF2_SEEKERMISSILE) misl->tracer=linetarget; - if (!AimAtAngle) + if (linetarget && (misl->flags2 & MF2_SEEKERMISSILE)) + misl->tracer = linetarget; + if (!aimatangle) { // This original implementation is to aim straight ahead and then offset // the angle from the resulting direction. FVector3 velocity(misl->velx, misl->vely, 0); fixed_t missilespeed = (fixed_t)velocity.Length(); - misl->angle += Angle; + misl->angle += angle; angle_t an = misl->angle >> ANGLETOFINESHIFT; misl->velx = FixedMul (missilespeed, finecosine[an]); misl->vely = FixedMul (missilespeed, finesine[an]); } } } + return 0; } @@ -1067,49 +1130,52 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireCustomMissile) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) { - ACTION_PARAM_START(5); - ACTION_PARAM_INT(Damage, 0); - ACTION_PARAM_BOOL(norandom, 1); - ACTION_PARAM_BOOL(UseAmmo, 2); - ACTION_PARAM_CLASS(PuffType, 3); - ACTION_PARAM_FIXED(Range, 4); + PARAM_ACTION_PROLOGUE; + PARAM_INT (damage); + PARAM_BOOL_OPT (norandom) { norandom = false; } + PARAM_BOOL_OPT (useammo) { useammo = true; } + PARAM_CLASS_OPT (pufftype, AActor) { pufftype = NULL; } + PARAM_FIXED_OPT (range) { range = 0; } - if (!self->player) return; + if (!self->player) + return 0; - player_t *player=self->player; - AWeapon * weapon=player->ReadyWeapon; + player_t *player = self->player; + AWeapon *weapon = player->ReadyWeapon; angle_t angle; int pitch; AActor * linetarget; - if (!norandom) Damage *= (pr_cwpunch()%8+1); + if (!norandom) + damage *= pr_cwpunch() % 8 + 1; angle = self->angle + (pr_cwpunch.Random2() << 18); - if (Range == 0) Range = MELEERANGE; - pitch = P_AimLineAttack (self, angle, Range, &linetarget); + if (range == 0) + range = MELEERANGE; + pitch = P_AimLineAttack (self, angle, range, &linetarget); // only use ammo when actually hitting something! - if (UseAmmo && linetarget && weapon) + if (useammo && linetarget && weapon) { - if (!weapon->DepleteAmmo(weapon->bAltFire, true)) return; // out of ammo + if (!weapon->DepleteAmmo(weapon->bAltFire, true)) + return 0; // out of ammo } - if (!PuffType) PuffType = PClass::FindClass(NAME_BulletPuff); + if (pufftype == NULL) + pufftype = PClass::FindClass(NAME_BulletPuff); - P_LineAttack (self, angle, Range, pitch, Damage, GetDefaultByType(PuffType)->DamageType, PuffType, true); + P_LineAttack (self, angle, range, pitch, damage, GetDefaultByType(pufftype)->DamageType, pufftype, true); // turn to face target if (linetarget) { S_Sound (self, CHAN_WEAPON, weapon->AttackSound, 1, ATTN_NORM); - self->angle = R_PointToAngle2 (self->x, - self->y, - linetarget->x, - linetarget->y); + self->angle = R_PointToAngle2 (self->x, self->y, linetarget->x, linetarget->y); } + return 0; } @@ -1126,27 +1192,30 @@ enum //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack) { - ACTION_PARAM_START(8); - ACTION_PARAM_INT(Damage, 0); - ACTION_PARAM_INT(Spawnofs_XY, 1); - ACTION_PARAM_BOOL(UseAmmo, 2); - ACTION_PARAM_COLOR(Color1, 3); - ACTION_PARAM_COLOR(Color2, 4); - ACTION_PARAM_INT(Flags, 5); - ACTION_PARAM_FLOAT(MaxDiff, 6); - ACTION_PARAM_CLASS(PuffType, 7); + PARAM_ACTION_PROLOGUE; + PARAM_INT (damage); + PARAM_INT_OPT (spawnofs_xy) { spawnofs_xy = 0; } + PARAM_BOOL_OPT (useammo) { useammo = true; } + PARAM_COLOR_OPT (color1) { color1 = 0; } + PARAM_COLOR_OPT (color2) { color2 = 0; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_FLOAT_OPT (maxdiff) { maxdiff = 0; } + PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindClass(NAME_BulletPuff); } - if (!self->player) return; + if (!self->player) + return 0; - AWeapon * weapon=self->player->ReadyWeapon; + AWeapon *weapon = self->player->ReadyWeapon; // only use ammo when actually hitting something! - if (UseAmmo) + if (useammo) { - if (!weapon->DepleteAmmo(weapon->bAltFire, true)) return; // out of ammo + if (!weapon->DepleteAmmo(weapon->bAltFire, true)) + return 0; // out of ammo } - P_RailAttack (self, Damage, Spawnofs_XY, Color1, Color2, MaxDiff, (Flags & RAF_SILENT), PuffType, (!(Flags & RAF_NOPIERCE))); + P_RailAttack (self, damage, spawnofs_xy, color1, color2, float(maxdiff), (flags & RAF_SILENT), pufftype, (!(flags & RAF_NOPIERCE))); + return 0; } //========================================================================== @@ -1163,15 +1232,15 @@ enum DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) { - ACTION_PARAM_START(8); - ACTION_PARAM_INT(Damage, 0); - ACTION_PARAM_INT(Spawnofs_XY, 1); - ACTION_PARAM_COLOR(Color1, 2); - ACTION_PARAM_COLOR(Color2, 3); - ACTION_PARAM_INT(Flags, 4); - ACTION_PARAM_INT(aim, 5); - ACTION_PARAM_FLOAT(MaxDiff, 6); - ACTION_PARAM_CLASS(PuffType, 7); + PARAM_ACTION_PROLOGUE; + PARAM_INT (damage); + PARAM_INT_OPT (spawnofs_xy) { spawnofs_xy = 0; } + PARAM_COLOR_OPT (color1) { color1 = 0; } + PARAM_COLOR_OPT (color2) { color2 = 0; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_INT_OPT (aim) { aim = CRF_DONTAIM; } + PARAM_FLOAT_OPT (maxdiff) { maxdiff = 0; } + PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindClass(NAME_BulletPuff); } fixed_t saved_x = self->x; fixed_t saved_y = self->y; @@ -1179,7 +1248,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) if (aim && self->target == NULL) { - return; + return 0; } // [RH] Andy Baker's stealth monsters if (self->flags & MF_STEALTH) @@ -1192,12 +1261,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) if (aim) { - self->angle = R_PointToAngle2 (self->x, self->y, self->target->x, self->target->y); - } self->pitch = P_AimLineAttack (self, self->angle, MISSILERANGE); @@ -1213,9 +1280,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) { // Tricky: We must offset to the angle of the current position // but then change the angle again to ensure proper aim. - self->x += Spawnofs_XY * finecosine[self->angle]; - self->y += Spawnofs_XY * finesine[self->angle]; - Spawnofs_XY = 0; + self->x += spawnofs_xy * finecosine[self->angle]; + self->y += spawnofs_xy * finesine[self->angle]; + spawnofs_xy = 0; self->angle = R_PointToAngle2 (self->x, self->y, self->target->x - self->target->velx * 3, self->target->y - self->target->vely * 3); @@ -1231,11 +1298,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) angle_t angle = (self->angle - ANG90) >> ANGLETOFINESHIFT; - P_RailAttack (self, Damage, Spawnofs_XY, Color1, Color2, MaxDiff, (Flags & RAF_SILENT), PuffType, (!(Flags & RAF_NOPIERCE))); + P_RailAttack (self, damage, spawnofs_xy, color1, color2, float(maxdiff), flags & RAF_SILENT, pufftype, !(flags & RAF_NOPIERCE)); self->x = saved_x; self->y = saved_y; self->angle = saved_angle; + return 0; } //=========================================================================== @@ -1244,19 +1312,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) // //=========================================================================== -static void DoGiveInventory(AActor * receiver, DECLARE_PARAMINFO) +static void DoGiveInventory(AActor *receiver, StateCallData *statecall, VM_ARGS) { - ACTION_PARAM_START(2); - ACTION_PARAM_CLASS(mi, 0); - ACTION_PARAM_INT(amount, 1); + int pnum = NAP; + PARAM_CLASS (mi, AInventory); + PARAM_INT_OPT (amount) { amount = 1; } - bool res=true; + bool res = true; if (receiver == NULL) return; - if (amount==0) amount=1; + if (amount <= 0) + { + amount = 1; + } if (mi) { - AInventory *item = static_cast<AInventory *>(Spawn (mi, 0, 0, 0, NO_REPLACE)); + AInventory *item = static_cast<AInventory *>(Spawn(mi, 0, 0, 0, NO_REPLACE)); if (item->IsKindOf(RUNTIME_CLASS(AHealth))) { item->Amount *= amount; @@ -1268,30 +1339,39 @@ static void DoGiveInventory(AActor * receiver, DECLARE_PARAMINFO) item->flags |= MF_DROPPED; if (item->flags & MF_COUNTITEM) { - item->flags&=~MF_COUNTITEM; + item->flags &= ~MF_COUNTITEM; level.total_items--; } - if (!item->CallTryPickup (receiver)) + if (!item->CallTryPickup(receiver)) { - item->Destroy (); + item->Destroy(); res = false; } - else res = true; + else + { + res = true; + } + } + else + { + res = false; } - else res = false; ACTION_SET_RESULT(res); - } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveInventory) { - DoGiveInventory(self, PUSH_PARAMINFO); + PARAM_ACTION_PROLOGUE; + DoGiveInventory(self, statecall, VM_ARGS_NAMES); + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToTarget) { - DoGiveInventory(self->target, PUSH_PARAMINFO); -} + PARAM_ACTION_PROLOGUE; + DoGiveInventory(self->target, statecall, VM_ARGS_NAMES); + return 0; +} //=========================================================================== // @@ -1299,17 +1379,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToTarget) // //=========================================================================== -void DoTakeInventory(AActor * receiver, DECLARE_PARAMINFO) +void DoTakeInventory(AActor *receiver, StateCallData *statecall, VM_ARGS) { - ACTION_PARAM_START(2); - ACTION_PARAM_CLASS(item, 0); - ACTION_PARAM_INT(amount, 1); + int pnum = NAP; + PARAM_CLASS (itemtype, AInventory); + PARAM_INT_OPT (amount) { amount = 0; } - if (item == NULL || receiver == NULL) return; + if (itemtype == NULL || receiver == NULL) return; bool res = false; - AInventory * inv = receiver->FindInventory(item); + AInventory *inv = receiver->FindInventory(itemtype); if (inv && !inv->IsKindOf(RUNTIME_CLASS(AHexenArmor))) { @@ -1317,24 +1397,33 @@ void DoTakeInventory(AActor * receiver, DECLARE_PARAMINFO) { res = true; } - if (!amount || amount>=inv->Amount) + if (amount == 0 || amount >= inv->Amount) { - if (inv->ItemFlags&IF_KEEPDEPLETED) inv->Amount=0; - else inv->Destroy(); + if (inv->ItemFlags & IF_KEEPDEPLETED) + inv->Amount = 0; + else + inv->Destroy(); + } + else + { + inv->Amount -= amount; } - else inv->Amount-=amount; } ACTION_SET_RESULT(res); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeInventory) { - DoTakeInventory(self, PUSH_PARAMINFO); + PARAM_ACTION_PROLOGUE; + DoTakeInventory(self, statecall, VM_ARGS_NAMES); + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeFromTarget) { - DoTakeInventory(self->target, PUSH_PARAMINFO); + PARAM_ACTION_PROLOGUE; + DoTakeInventory(self->target, statecall, VM_ARGS_NAMES); + return 0; } //=========================================================================== @@ -1441,45 +1530,49 @@ static bool InitSpawnedItem(AActor *self, AActor *mo, int flags) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItem) { - ACTION_PARAM_START(5); - ACTION_PARAM_CLASS(missile, 0); - ACTION_PARAM_FIXED(distance, 1); - ACTION_PARAM_FIXED(zheight, 2); - ACTION_PARAM_BOOL(useammo, 3); - ACTION_PARAM_BOOL(transfer_translation, 4); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT (missile, AActor) { missile = PClass::FindClass("Unknown"); } + PARAM_FIXED_OPT (distance) { distance = 0; } + PARAM_FIXED_OPT (zheight) { zheight = 0; } + PARAM_BOOL_OPT (useammo) { useammo = true; } + PARAM_BOOL_OPT (transfer_translation) { transfer_translation = false; } - if (!missile) + if (missile == NULL) { ACTION_SET_RESULT(false); - return; + return 0; } // Don't spawn monsters if this actor has been massacred - if (self->DamageType == NAME_Massacre && GetDefaultByType(missile)->flags3&MF3_ISMONSTER) return; + if (self->DamageType == NAME_Massacre && (GetDefaultByType(missile)->flags3 & MF3_ISMONSTER)) + return 0; - if (distance==0) + if (distance == 0) { // use the minimum distance that does not result in an overlap - distance=(self->radius+GetDefaultByType(missile)->radius)>>FRACBITS; + distance = (self->radius + GetDefaultByType(missile)->radius) >> FRACBITS; } if (ACTION_CALL_FROM_WEAPON()) { - // Used from a weapon so use some ammo - AWeapon * weapon=self->player->ReadyWeapon; + // Used from a weapon, so use some ammo + AWeapon *weapon = self->player->ReadyWeapon; - if (!weapon) return; - if (useammo && !weapon->DepleteAmmo(weapon->bAltFire)) return; + if (weapon == NULL) + return 0; + if (useammo && !weapon->DepleteAmmo(weapon->bAltFire)) + return 0; } - AActor * mo = Spawn( missile, + AActor *mo = Spawn(missile, self->x + FixedMul(distance, finecosine[self->angle>>ANGLETOFINESHIFT]), self->y + FixedMul(distance, finesine[self->angle>>ANGLETOFINESHIFT]), self->z - self->floorclip + zheight, ALLOW_REPLACE); - int flags = (transfer_translation? SIXF_TRANSFERTRANSLATION:0) + (useammo? SIXF_SETMASTER:0); + int flags = (transfer_translation ? SIXF_TRANSFERTRANSLATION : 0) + (useammo ? SIXF_SETMASTER : 0); bool res = InitSpawnedItem(self, mo, flags); ACTION_SET_RESULT(res); // for an inventory item's use state + return 0; } //=========================================================================== @@ -1491,37 +1584,39 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItem) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) { - ACTION_PARAM_START(10); - ACTION_PARAM_CLASS(missile, 0); - ACTION_PARAM_FIXED(xofs, 1); - ACTION_PARAM_FIXED(yofs, 2); - ACTION_PARAM_FIXED(zofs, 3); - ACTION_PARAM_FIXED(xvel, 4); - ACTION_PARAM_FIXED(yvel, 5); - ACTION_PARAM_FIXED(zvel, 6); - ACTION_PARAM_ANGLE(Angle, 7); - ACTION_PARAM_INT(flags, 8); - ACTION_PARAM_INT(chance, 9); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS (missile, AActor); + PARAM_FIXED_OPT (xofs) { xofs = 0; } + PARAM_FIXED_OPT (yofs) { yofs = 0; } + PARAM_FIXED_OPT (zofs) { zofs = 0; } + PARAM_FIXED_OPT (xvel) { xvel = 0; } + PARAM_FIXED_OPT (yvel) { yvel = 0; } + PARAM_FIXED_OPT (zvel) { zvel = 0; } + PARAM_ANGLE_OPT (angle) { angle = 0; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_INT_OPT (chance) { chance = 0; } - if (!missile) + if (missile == NULL) { ACTION_SET_RESULT(false); - return; + return 0; } - if (chance > 0 && pr_spawnitemex()<chance) return; + if (chance > 0 && pr_spawnitemex() < chance) + return 0; // Don't spawn monsters if this actor has been massacred - if (self->DamageType == NAME_Massacre && GetDefaultByType(missile)->flags3&MF3_ISMONSTER) return; + if (self->DamageType == NAME_Massacre && (GetDefaultByType(missile)->flags3 & MF3_ISMONSTER)) + return 0; - fixed_t x,y; + fixed_t x, y; if (!(flags & SIXF_ABSOLUTEANGLE)) { - Angle += self->angle; + angle += self->angle; } - angle_t ang = Angle >> ANGLETOFINESHIFT; + angle_t ang = angle >> ANGLETOFINESHIFT; if (flags & SIXF_ABSOLUTEPOSITION) { @@ -1544,7 +1639,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) xvel = newxvel; } - AActor * mo = Spawn(missile, x, y, self->z - self->floorclip + zofs, ALLOW_REPLACE); + AActor *mo = Spawn(missile, x, y, self->z - self->floorclip + zofs, ALLOW_REPLACE); bool res = InitSpawnedItem(self, mo, flags); ACTION_SET_RESULT(res); // for an inventory item's use state if (mo) @@ -1552,10 +1647,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) mo->velx = xvel; mo->vely = yvel; mo->velz = zvel; - mo->angle = Angle; + mo->angle = angle; if (flags & SIXF_TRANSFERAMBUSHFLAG) - mo->flags = (mo->flags&~MF_AMBUSH) | (self->flags & MF_AMBUSH); + mo->flags = (mo->flags & ~MF_AMBUSH) | (self->flags & MF_AMBUSH); } + return 0; } //=========================================================================== @@ -1567,29 +1663,31 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ThrowGrenade) { - ACTION_PARAM_START(5); - ACTION_PARAM_CLASS(missile, 0); - ACTION_PARAM_FIXED(zheight, 1); - ACTION_PARAM_FIXED(xyvel, 2); - ACTION_PARAM_FIXED(zvel, 3); - ACTION_PARAM_BOOL(useammo, 4); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS (missile, AActor); + PARAM_FIXED_OPT (zheight) { zheight = 0; } + PARAM_FIXED_OPT (xyvel) { xyvel = 0; } + PARAM_FIXED_OPT (zvel) { zvel = 0; } + PARAM_BOOL_OPT (useammo) { useammo = true; } - if (missile == NULL) return; + if (missile == NULL) + return 0; if (ACTION_CALL_FROM_WEAPON()) { - // Used from a weapon so use some ammo - AWeapon * weapon=self->player->ReadyWeapon; + // Used from a weapon, so use some ammo + AWeapon *weapon = self->player->ReadyWeapon; - if (!weapon) return; - if (useammo && !weapon->DepleteAmmo(weapon->bAltFire)) return; + if (weapon == NULL) + return 0; + if (useammo && !weapon->DepleteAmmo(weapon->bAltFire)) + return 0; } - - AActor * bo; + AActor *bo; bo = Spawn(missile, self->x, self->y, - self->z - self->floorclip + zheight + 35*FRACUNIT + (self->player? self->player->crouchoffset : 0), + self->z - self->floorclip + zheight + 35*FRACUNIT + (self->player ? self->player->crouchoffset : 0), ALLOW_REPLACE); if (bo) { @@ -1607,7 +1705,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ThrowGrenade) bo->target= self; P_CheckMissileSpawn (bo); } - else ACTION_SET_RESULT(false); + else + { + ACTION_SET_RESULT(false); + } + return 0; } @@ -1618,13 +1720,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ThrowGrenade) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Recoil) { - ACTION_PARAM_START(1); - ACTION_PARAM_FIXED(xyvel, 0); + PARAM_ACTION_PROLOGUE; + PARAM_FIXED(xyvel); angle_t angle = self->angle + ANG180; angle >>= ANGLETOFINESHIFT; - self->velx += FixedMul (xyvel, finecosine[angle]); - self->vely += FixedMul (xyvel, finesine[angle]); + self->velx += FixedMul(xyvel, finecosine[angle]); + self->vely += FixedMul(xyvel, finesine[angle]); + return 0; } @@ -1635,16 +1738,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Recoil) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SelectWeapon) { - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(cls, 0); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS(cls, AWeapon); if (cls == NULL || self->player == NULL) { ACTION_SET_RESULT(false); - return; + return 0; } - AWeapon * weaponitem = static_cast<AWeapon*>(self->FindInventory(cls)); + AWeapon *weaponitem = static_cast<AWeapon*>(self->FindInventory(cls)); if (weaponitem != NULL && weaponitem->IsKindOf(RUNTIME_CLASS(AWeapon))) { @@ -1653,8 +1756,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SelectWeapon) self->player->PendingWeapon = weaponitem; } } - else ACTION_SET_RESULT(false); - + else + { + ACTION_SET_RESULT(false); + } + return 0; } @@ -1667,13 +1773,13 @@ EXTERN_CVAR(Float, con_midtime) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Print) { - ACTION_PARAM_START(3); - ACTION_PARAM_STRING(text, 0); - ACTION_PARAM_FLOAT(time, 1); - ACTION_PARAM_NAME(fontname, 2); + PARAM_ACTION_PROLOGUE; + PARAM_STRING (text); + PARAM_FLOAT_OPT (time) { time = 0; } + PARAM_NAME_OPT (fontname) { fontname = NAME_None; } if (self->CheckLocalView (consoleplayer) || - (self->target!=NULL && self->target->CheckLocalView (consoleplayer))) + (self->target != NULL && self->target->CheckLocalView (consoleplayer))) { float saved = con_midtime; FFont *font = NULL; @@ -1684,12 +1790,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Print) } if (time > 0) { - con_midtime = time; + con_midtime = float(time); } - C_MidPrint(font != NULL ? font : SmallFont, text); con_midtime = saved; } + return 0; } //=========================================================================== @@ -1700,10 +1806,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Print) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PrintBold) { - ACTION_PARAM_START(3); - ACTION_PARAM_STRING(text, 0); - ACTION_PARAM_FLOAT(time, 1); - ACTION_PARAM_NAME(fontname, 2); + PARAM_ACTION_PROLOGUE; + PARAM_STRING (text); + PARAM_FLOAT_OPT (time) { time = 0; } + PARAM_NAME_OPT (fontname) { fontname = NAME_None; } float saved = con_midtime; FFont *font = NULL; @@ -1714,11 +1820,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PrintBold) } if (time > 0) { - con_midtime = time; + con_midtime = float(time); } - C_MidPrintBold(font != NULL ? font : SmallFont, text); con_midtime = saved; + return 0; } //=========================================================================== @@ -1729,9 +1835,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PrintBold) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Log) { - ACTION_PARAM_START(1); - ACTION_PARAM_STRING(text, 0); + PARAM_ACTION_PROLOGUE; + PARAM_STRING(text); Printf("%s\n", text); + return 0; } //=========================================================================== @@ -1741,15 +1848,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Log) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTranslucent) { - ACTION_PARAM_START(2); - ACTION_PARAM_FIXED(alpha, 0); - ACTION_PARAM_INT(mode, 1); + PARAM_ACTION_PROLOGUE; + PARAM_FIXED (alpha); + PARAM_INT_OPT (mode) { mode = 0; } mode = mode == 0 ? STYLE_Translucent : mode == 2 ? STYLE_Fuzzy : STYLE_Add; self->RenderStyle.Flags &= ~STYLEF_Alpha1; self->alpha = clamp<fixed_t>(alpha, 0, FRACUNIT); self->RenderStyle = ERenderStyle(mode); + return 0; } //=========================================================================== @@ -1761,14 +1869,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTranslucent) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeIn) { - ACTION_PARAM_START(1); - ACTION_PARAM_FIXED(reduce, 0); + PARAM_ACTION_PROLOGUE; + PARAM_FIXED_OPT(reduce) { reduce = FRACUNIT/10; } - if (reduce == 0) reduce = FRACUNIT/10; + if (reduce == 0) + reduce = FRACUNIT/10; self->RenderStyle.Flags &= ~STYLEF_Alpha1; self->alpha += reduce; - //if (self->alpha<=0) self->Destroy(); + return 0; } //=========================================================================== @@ -1780,15 +1889,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeIn) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeOut) { - ACTION_PARAM_START(2); - ACTION_PARAM_FIXED(reduce, 0); - ACTION_PARAM_BOOL(remove, 1); + PARAM_ACTION_PROLOGUE; + PARAM_FIXED_OPT(reduce) { reduce = FRACUNIT/10; } + PARAM_BOOL_OPT(remove) { remove = true; } - if (reduce == 0) reduce = FRACUNIT/10; + if (reduce == 0) + reduce = FRACUNIT/10; self->RenderStyle.Flags &= ~STYLEF_Alpha1; self->alpha -= reduce; - if (self->alpha<=0 && remove) self->Destroy(); + if (self->alpha<=0 && remove) + self->Destroy(); + return 0; } //=========================================================================== @@ -1798,20 +1910,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeOut) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnDebris) { + PARAM_ACTION_PROLOGUE; + PARAM_CLASS (debris, AActor); + PARAM_BOOL_OPT (transfer_translation) { transfer_translation = false; } + PARAM_FIXED_OPT (mult_h) { mult_h = FRACUNIT; } + PARAM_FIXED_OPT (mult_v) { mult_v = FRACUNIT; } int i; - AActor * mo; + AActor *mo; - ACTION_PARAM_START(4); - ACTION_PARAM_CLASS(debris, 0); - ACTION_PARAM_BOOL(transfer_translation, 1); - ACTION_PARAM_FIXED(mult_h, 2); - ACTION_PARAM_FIXED(mult_v, 3); - - if (debris == NULL) return; + if (debris == NULL) + return 0; // only positive values make sense here - if (mult_v<=0) mult_v=FRACUNIT; - if (mult_h<=0) mult_h=FRACUNIT; + if (mult_v <= 0) + mult_v = FRACUNIT; + if (mult_h <= 0) + mult_h = FRACUNIT; for (i = 0; i < GetDefaultByType(debris)->health; i++) { @@ -1830,6 +1944,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnDebris) mo->vely = FixedMul(mult_h, pr_spawndebris.Random2()<<(FRACBITS-6)); } } + return 0; } @@ -1841,18 +1956,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnDebris) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSight) { - ACTION_PARAM_START(1); - ACTION_PARAM_STATE(jump, 0); + PARAM_ACTION_PROLOGUE; + PARAM_STATE(jump); ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - for (int i=0;i<MAXPLAYERS;i++) + for (int i = 0; i < MAXPLAYERS; i++) { - if (playeringame[i] && P_CheckSight(players[i].camera,self,true)) return; + if (playeringame[i] && P_CheckSight(players[i].camera, self, true)) + return 0; } ACTION_JUMP(jump); - + return 0; } @@ -1863,17 +1979,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSight) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DropInventory) { - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(drop, 0); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS(drop, AInventory); if (drop) { - AInventory * inv = self->FindInventory(drop); + AInventory *inv = self->FindInventory(drop); if (inv) { self->DropInventory(inv); } } + return 0; } @@ -1884,20 +2001,23 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DropInventory) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetBlend) { - ACTION_PARAM_START(4); - ACTION_PARAM_COLOR(color, 0); - ACTION_PARAM_FLOAT(alpha, 1); - ACTION_PARAM_INT(tics, 2); - ACTION_PARAM_COLOR(color2, 3); + PARAM_ACTION_PROLOGUE; + PARAM_COLOR (color); + PARAM_FLOAT (alpha); + PARAM_INT (tics); + PARAM_COLOR_OPT (color2) { color2 = 0; } - if (color == MAKEARGB(255,255,255,255)) color=0; - if (color2 == MAKEARGB(255,255,255,255)) color2=0; - if (!color2.a) + if (color == MAKEARGB(255,255,255,255)) + color = 0; + if (color2 == MAKEARGB(255,255,255,255)) + color2 = 0; + if (color2.a == 0) color2 = color; - new DFlashFader(color.r/255.0f, color.g/255.0f, color.b/255.0f, alpha, - color2.r/255.0f, color2.g/255.0f, color2.b/255.0f, 0, - (float)tics/TICRATE, self); + new DFlashFader(color.r/255.f, color.g/255.f, color.b/255.f, float(alpha), + color2.r/255.f, color2.g/255.f, color2.b/255.f, 0, + float(tics)/TICRATE, self); + return 0; } @@ -1908,13 +2028,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetBlend) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIf) { - ACTION_PARAM_START(2); - ACTION_PARAM_BOOL(expression, 0); - ACTION_PARAM_STATE(jump, 1); + PARAM_ACTION_PROLOGUE; + PARAM_BOOL (condition); + PARAM_STATE (jump); ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - if (expression) ACTION_JUMP(jump); - + if (condition) + ACTION_JUMP(jump); + return 0; } //=========================================================================== @@ -1924,10 +2045,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIf) //=========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_KillMaster) { + PARAM_ACTION_PROLOGUE; if (self->master != NULL) { P_DamageMobj(self->master, self, self, self->master->health, NAME_None, DMG_NO_ARMOR); } + return 0; } //=========================================================================== @@ -1937,8 +2060,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_KillMaster) //=========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_KillChildren) { + PARAM_ACTION_PROLOGUE; TThinkerIterator<AActor> it; - AActor * mo; + AActor *mo; while ( (mo = it.Next()) ) { @@ -1947,6 +2071,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KillChildren) P_DamageMobj(mo, self, self, mo->health, NAME_None, DMG_NO_ARMOR); } } + return 0; } //=========================================================================== @@ -1956,8 +2081,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_KillChildren) //=========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_KillSiblings) { + PARAM_ACTION_PROLOGUE; TThinkerIterator<AActor> it; - AActor * mo; + AActor *mo; while ( (mo = it.Next()) ) { @@ -1966,6 +2092,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KillSiblings) P_DamageMobj(mo, self, self, mo->health, NAME_None, DMG_NO_ARMOR); } } + return 0; } //=========================================================================== @@ -1975,26 +2102,28 @@ DEFINE_ACTION_FUNCTION(AActor, A_KillSiblings) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CountdownArg) { - ACTION_PARAM_START(1); - ACTION_PARAM_INT(cnt, 0); + PARAM_ACTION_PROLOGUE; + PARAM_INT(argnum); - if (cnt<0 || cnt>=5) return; - if (!self->args[cnt]--) + if (argnum > 0 && argnum < countof(self->args)) { - if (self->flags&MF_MISSILE) + if (!self->args[argnum]--) { - P_ExplodeMissile(self, NULL, NULL); - } - else if (self->flags&MF_SHOOTABLE) - { - P_DamageMobj (self, NULL, NULL, self->health, NAME_None, DMG_FORCED); - } - else - { - self->SetState(self->FindState(NAME_Death)); + if (self->flags & MF_MISSILE) + { + P_ExplodeMissile(self, NULL, NULL); + } + else if (self->flags & MF_SHOOTABLE) + { + P_DamageMobj(self, NULL, NULL, self->health, NAME_None, DMG_FORCED); + } + else + { + self->SetState(self->FindState(NAME_Death)); + } } } - + return 0; } //============================================================================ @@ -2005,13 +2134,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CountdownArg) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Burst) { - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(chunk, 0); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS(chunk, AActor); int i, numChunks; - AActor * mo; + AActor *mo; - if (chunk == NULL) return; + if (chunk == NULL) + return 0; self->velx = self->vely = self->velz = 0; self->height = self->GetDefault()->height; @@ -2048,7 +2178,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Burst) } CALL_ACTION(A_NoBlocking, self); - self->Destroy (); + self->Destroy(); + return 0; } //=========================================================================== @@ -2059,34 +2190,34 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Burst) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckFloor) { - ACTION_PARAM_START(1); - ACTION_PARAM_STATE(jump, 0); + PARAM_ACTION_PROLOGUE; + PARAM_STATE(jump); ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! if (self->z <= self->floorz) { ACTION_JUMP(jump); } - + return 0; } //=========================================================================== // // A_CheckCeiling -// [GZ] Totally copied on A_CheckFloor, jumps if actor touches ceiling +// [GZ] Totally copied from A_CheckFloor, jumps if actor touches ceiling // //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckCeiling) { - ACTION_PARAM_START(1); - ACTION_PARAM_STATE(jump, 0); + PARAM_ACTION_PROLOGUE; + PARAM_STATE(jump); ACTION_SET_RESULT(false); - if (self->z+self->height >= self->ceilingz) // Height needs to be counted + if (self->z + self->height >= self->ceilingz) // Height needs to be counted { ACTION_JUMP(jump); } - + return 0; } //=========================================================================== @@ -2097,12 +2228,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckCeiling) //=========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_Stop) { + PARAM_ACTION_PROLOGUE; self->velx = self->vely = self->velz = 0; if (self->player && self->player->mo == self && !(self->player->cheats & CF_PREDICTING)) { self->player->mo->PlayIdle(); self->player->velx = self->player->vely = 0; } + return 0; } static void CheckStopped(AActor *self) @@ -2132,8 +2265,8 @@ enum RS_Flags DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn) { - ACTION_PARAM_START(1); - ACTION_PARAM_INT(flags, 0); + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT(flags) { flags = RSF_FOG; } fixed_t x = self->SpawnPoint[0]; fixed_t y = self->SpawnPoint[1]; @@ -2147,12 +2280,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn) if (flags & RSF_TELEFRAG) { // [KS] DIE DIE DIE DIE erm *ahem* =) - if (P_TeleportMove (self, x, y, sec->floorplane.ZatPoint (x, y), true)) oktorespawn = true; + if (P_TeleportMove(self, x, y, sec->floorplane.ZatPoint (x, y), true)) + oktorespawn = true; } else { - self->SetOrigin (x, y, sec->floorplane.ZatPoint (x, y)); - if (P_TestMobjLocation (self)) oktorespawn = true; + self->SetOrigin(x, y, sec->floorplane.ZatPoint (x, y)); + if (P_TestMobjLocation(self)) + oktorespawn = true; } if (oktorespawn) @@ -2171,8 +2306,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn) else { // Don't attack yourself (Re: "Marine targets itself after suicide") - if (self->target == self) self->target = NULL; - if (self->lastenemy == self) self->lastenemy = NULL; + if (self->target == self) + self->target = NULL; + if (self->lastenemy == self) + self->lastenemy = NULL; } self->flags = (defs->flags & ~MF_FRIENDLY) | (self->flags & MF_FRIENDLY); @@ -2185,14 +2322,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn) if (flags & RSF_FOG) { - Spawn<ATeleportFog> (x, y, self->z + TELEFOGHEIGHT, ALLOW_REPLACE); + Spawn<ATeleportFog>(x, y, self->z + TELEFOGHEIGHT, ALLOW_REPLACE); } - if (self->CountsAsKill()) level.total_monsters++; + if (self->CountsAsKill()) + level.total_monsters++; } else { self->flags &= ~MF_SOLID; } + return 0; } @@ -2204,8 +2343,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlayerSkinCheck) { - ACTION_PARAM_START(1); - ACTION_PARAM_STATE(jump, 0); + PARAM_ACTION_PROLOGUE; + PARAM_STATE(jump); ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! if (self->player != NULL && @@ -2213,6 +2352,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlayerSkinCheck) { ACTION_JUMP(jump); } + return 0; } //=========================================================================== @@ -2222,10 +2362,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlayerSkinCheck) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetGravity) { - ACTION_PARAM_START(1); - ACTION_PARAM_FIXED(val, 0); + PARAM_ACTION_PROLOGUE; + PARAM_FIXED(gravity); - self->gravity = clamp<fixed_t> (val, 0, FRACUNIT*10); + self->gravity = clamp<fixed_t>(gravity, 0, FRACUNIT*10); + return 0; } @@ -2239,9 +2380,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetGravity) DEFINE_ACTION_FUNCTION(AActor, A_ClearTarget) { + PARAM_ACTION_PROLOGUE; self->target = NULL; self->LastHeard = NULL; self->lastenemy = NULL; + return 0; } //========================================================================== @@ -2259,10 +2402,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_ClearTarget) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) { - ACTION_PARAM_START(3); - ACTION_PARAM_STATE(jump, 0); - ACTION_PARAM_ANGLE(fov, 1); - ACTION_PARAM_BOOL(projtarg, 2); + PARAM_ACTION_PROLOGUE; + PARAM_STATE (jump); + PARAM_ANGLE_OPT (fov) { fov = 0; } + PARAM_BOOL_OPT (projtarg) { projtarg = false; } angle_t an; AActor *target; @@ -2283,22 +2426,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) target = self->target; } - if (!target) return; // [KS] Let's not call P_CheckSight unnecessarily in this case. + if (target == NULL) + return 0; // [KS] Let's not call P_CheckSight unnecessarily in this case. if (!P_CheckSight (self, target, 1)) - return; + return 0; if (fov && (fov < ANGLE_MAX)) { - an = R_PointToAngle2 (self->x, - self->y, - target->x, - target->y) - - self->angle; + an = R_PointToAngle2(self->x, self->y, target->x, target->y) - self->angle; if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2))) { - return; // [KS] Outside of FOV - return + return 0; // [KS] Outside of FOV - return } } @@ -2309,9 +2449,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) P_BulletSlope(self, &target); } - if (!target) return; + if (target == NULL) + return 0; ACTION_JUMP(jump); + return 0; } @@ -2324,10 +2466,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) { - ACTION_PARAM_START(3); - ACTION_PARAM_STATE(jump, 0); - ACTION_PARAM_ANGLE(fov, 1); - ACTION_PARAM_BOOL(projtarg, 2); + PARAM_ACTION_PROLOGUE; + PARAM_STATE (jump); + PARAM_ANGLE_OPT (fov) { fov = 0; } + PARAM_BOOL_OPT (projtarg) { projtarg = false; } angle_t an; AActor *target; @@ -2346,27 +2488,23 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) target = self->target; } - if (!target) return; // [KS] Let's not call P_CheckSight unnecessarily in this case. + if (target == NULL) + return 0; // [KS] Let's not call P_CheckSight unnecessarily in this case. if (!P_CheckSight (target, self, 1)) - return; + return 0; if (fov && (fov < ANGLE_MAX)) { - an = R_PointToAngle2 (self->x, - self->y, - target->x, - target->y) - - self->angle; + an = R_PointToAngle2(self->x, self->y, target->x, target->y) - self->angle; if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2))) { - return; // [KS] Outside of FOV - return + return 0; // [KS] Outside of FOV - return } - } - ACTION_JUMP(jump); + return 0; } @@ -2378,15 +2516,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageMaster) { - ACTION_PARAM_START(2); - ACTION_PARAM_INT(amount, 0); - ACTION_PARAM_NAME(DamageType, 1); + PARAM_ACTION_PROLOGUE; + PARAM_INT (amount); + PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } if (self->master != NULL) { if (amount > 0) { - P_DamageMobj(self->master, self, self, amount, DamageType, DMG_NO_ARMOR); + P_DamageMobj(self->master, self, self, amount, damagetype, DMG_NO_ARMOR); } else if (amount < 0) { @@ -2394,6 +2532,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageMaster) P_GiveBody(self->master, amount); } } + return 0; } //=========================================================================== @@ -2404,12 +2543,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageMaster) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageChildren) { - TThinkerIterator<AActor> it; - AActor * mo; + PARAM_ACTION_PROLOGUE; + PARAM_INT (amount); + PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } - ACTION_PARAM_START(2); - ACTION_PARAM_INT(amount, 0); - ACTION_PARAM_NAME(DamageType, 1); + TThinkerIterator<AActor> it; + AActor *mo; while ( (mo = it.Next()) ) { @@ -2417,7 +2556,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageChildren) { if (amount > 0) { - P_DamageMobj(mo, self, self, amount, DamageType, DMG_NO_ARMOR); + P_DamageMobj(mo, self, self, amount, damagetype, DMG_NO_ARMOR); } else if (amount < 0) { @@ -2426,6 +2565,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageChildren) } } } + return 0; } // [KS] *** End of my modifications *** @@ -2438,12 +2578,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageChildren) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageSiblings) { - TThinkerIterator<AActor> it; - AActor * mo; + PARAM_ACTION_PROLOGUE; + PARAM_INT (amount); + PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } - ACTION_PARAM_START(2); - ACTION_PARAM_INT(amount, 0); - ACTION_PARAM_NAME(DamageType, 1); + TThinkerIterator<AActor> it; + AActor *mo; while ( (mo = it.Next()) ) { @@ -2451,7 +2591,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageSiblings) { if (amount > 0) { - P_DamageMobj(mo, self, self, amount, DamageType, DMG_NO_ARMOR); + P_DamageMobj(mo, self, self, amount, damagetype, DMG_NO_ARMOR); } else if (amount < 0) { @@ -2460,6 +2600,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageSiblings) } } } + return 0; } @@ -2471,20 +2612,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageSiblings) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckForReload) { + PARAM_ACTION_PROLOGUE; + if ( self->player == NULL || self->player->ReadyWeapon == NULL ) - return; + return 0; - ACTION_PARAM_START(2); - ACTION_PARAM_INT(count, 0); - ACTION_PARAM_STATE(jump, 1); - ACTION_PARAM_BOOL(dontincrement, 2) + PARAM_INT (count); + PARAM_STATE (jump); + PARAM_BOOL_OPT (dontincrement) { dontincrement = false; } - if (count <= 0) return; + if (count <= 0) + return 0; AWeapon *weapon = self->player->ReadyWeapon; int ReloadCounter = weapon->ReloadCounter; - if(!dontincrement || ReloadCounter != 0) + if (!dontincrement || ReloadCounter != 0) ReloadCounter = (weapon->ReloadCounter+1) % count; else // 0 % 1 = 1? So how do we check if the weapon was never fired? We should only do this when we're not incrementing the counter though. ReloadCounter = 1; @@ -2498,11 +2641,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckForReload) else { // We need to reload. However, don't reload if we're out of ammo. - weapon->CheckAmmo( false, false ); + weapon->CheckAmmo(false, false); } - if(!dontincrement) + if (!dontincrement) weapon->ReloadCounter = ReloadCounter; + return 0; } //=========================================================================== @@ -2513,11 +2657,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckForReload) DEFINE_ACTION_FUNCTION(AActor, A_ResetReloadCounter) { - if ( self->player == NULL || self->player->ReadyWeapon == NULL ) - return; + PARAM_ACTION_PROLOGUE; + + if (self->player == NULL || self->player->ReadyWeapon == NULL) + return 0; AWeapon *weapon = self->player->ReadyWeapon; weapon->ReloadCounter = 0; + return 0; } //=========================================================================== @@ -2527,22 +2674,22 @@ DEFINE_ACTION_FUNCTION(AActor, A_ResetReloadCounter) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag) { - ACTION_PARAM_START(2); - ACTION_PARAM_STRING(flagname, 0); - ACTION_PARAM_BOOL(expression, 1); + PARAM_ACTION_PROLOGUE; + PARAM_STRING (flagname); + PARAM_BOOL (value); - const char *dot = strchr (flagname, '.'); + const char *dot = strchr(flagname, '.'); FFlagDef *fd; const PClass *cls = self->GetClass(); if (dot != NULL) { - FString part1(flagname, dot-flagname); - fd = FindFlag (cls, part1, dot+1); + FString part1(flagname.GetChars(), dot - flagname); + fd = FindFlag(cls, part1, dot + 1); } else { - fd = FindFlag (cls, flagname, NULL); + fd = FindFlag(cls, flagname, NULL); } if (fd != NULL) @@ -2555,7 +2702,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag) if (fd->structoffset == -1) { - HandleDeprecatedFlags(self, cls->ActorInfo, expression, fd->flagbit); + HandleDeprecatedFlags(self, cls->ActorInfo, value, fd->flagbit); } else { @@ -2565,7 +2712,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag) bool linkchange = flagp == &self->flags && (fd->flagbit == MF_NOBLOCKMAP || fd->flagbit == MF_NOSECTOR); if (linkchange) self->UnlinkFromWorld(); - if (expression) + if (value) { *flagp |= fd->flagbit; } @@ -2607,6 +2754,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag) { Printf("Unknown flag '%s' in '%s'\n", flagname, cls->TypeName.GetChars()); } + return 0; } //=========================================================================== @@ -2616,10 +2764,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag) //=========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_RemoveMaster) { - if (self->master != NULL) - { - P_RemoveThing(self->master); - } + PARAM_ACTION_PROLOGUE; + if (self->master != NULL) + { + P_RemoveThing(self->master); + } + return 0; } //=========================================================================== @@ -2629,18 +2779,20 @@ DEFINE_ACTION_FUNCTION(AActor, A_RemoveMaster) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveChildren) { - TThinkerIterator<AActor> it; - AActor * mo; - ACTION_PARAM_START(1); - ACTION_PARAM_BOOL(removeall,0); + PARAM_ACTION_PROLOGUE; + PARAM_BOOL_OPT(removeall) { removeall = false; } - while ( (mo = it.Next()) ) - { - if ( ( mo->master == self ) && ( ( mo->health <= 0 ) || removeall) ) - { - P_RemoveThing(mo); - } - } + TThinkerIterator<AActor> it; + AActor *mo; + + while ( (mo = it.Next()) ) + { + if ( ( mo->master == self ) && ( ( mo->health <= 0 ) || removeall) ) + { + P_RemoveThing(mo); + } + } + return 0; } //=========================================================================== @@ -2650,18 +2802,20 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveChildren) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveSiblings) { - TThinkerIterator<AActor> it; - AActor * mo; - ACTION_PARAM_START(1); - ACTION_PARAM_BOOL(removeall,0); + PARAM_ACTION_PROLOGUE; + PARAM_BOOL_OPT(removeall) { removeall = false; } - while ( (mo = it.Next()) ) - { - if ( ( mo->master == self->master ) && ( mo != self ) && ( ( mo->health <= 0 ) || removeall) ) - { - P_RemoveThing(mo); - } - } + TThinkerIterator<AActor> it; + AActor *mo; + + while ( (mo = it.Next()) ) + { + if ( ( mo->master == self->master ) && ( mo != self ) && ( ( mo->health <= 0 ) || removeall) ) + { + P_RemoveThing(mo); + } + } + return 0; } //=========================================================================== @@ -2671,10 +2825,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveSiblings) //=========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_RaiseMaster) { - if (self->master != NULL) - { - P_Thing_Raise(self->master); - } + PARAM_ACTION_PROLOGUE; + if (self->master != NULL) + { + P_Thing_Raise(self->master); + } + return 0; } //=========================================================================== @@ -2684,16 +2840,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseMaster) //=========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_RaiseChildren) { - TThinkerIterator<AActor> it; - AActor * mo; + PARAM_ACTION_PROLOGUE; - while ((mo = it.Next())) - { - if ( mo->master == self ) - { - P_Thing_Raise(mo); - } - } + TThinkerIterator<AActor> it; + AActor *mo; + + while ((mo = it.Next())) + { + if ( mo->master == self ) + { + P_Thing_Raise(mo); + } + } + return 0; } //=========================================================================== @@ -2703,16 +2862,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseChildren) //=========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_RaiseSiblings) { - TThinkerIterator<AActor> it; - AActor * mo; + PARAM_ACTION_PROLOGUE; - while ( (mo = it.Next()) ) - { - if ( ( mo->master == self->master ) && ( mo != self ) ) - { - P_Thing_Raise(mo); - } - } + TThinkerIterator<AActor> it; + AActor *mo; + + while ( (mo = it.Next()) ) + { + if ( ( mo->master == self->master ) && ( mo != self ) ) + { + P_Thing_Raise(mo); + } + } + return 0; } //=========================================================================== @@ -2724,23 +2886,24 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseSiblings) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MonsterRefire) { - ACTION_PARAM_START(2); - ACTION_PARAM_INT(prob, 0); - ACTION_PARAM_STATE(jump, 1); + PARAM_ACTION_PROLOGUE; + PARAM_INT (prob); + PARAM_STATE (jump); ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - A_FaceTarget (self); + A_FaceTarget(self); if (pr_monsterrefire() < prob) - return; + return 0; - if (!self->target + if (self->target == NULL || P_HitFriend (self) || self->target->health <= 0 - || !P_CheckSight (self, self->target, 0) ) + || !P_CheckSight(self, self->target, 0) ) { ACTION_JUMP(jump); } + return 0; } //=========================================================================== @@ -2753,9 +2916,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MonsterRefire) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetAngle) { - ACTION_PARAM_START(1); - ACTION_PARAM_ANGLE(angle, 0); + PARAM_ACTION_PROLOGUE; + PARAM_ANGLE_OPT(angle) { angle = 0; } self->angle = angle; + return 0; } //=========================================================================== @@ -2768,9 +2932,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetAngle) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetPitch) { - ACTION_PARAM_START(1); - ACTION_PARAM_ANGLE(pitch, 0); + PARAM_ACTION_PROLOGUE; + PARAM_ANGLE(pitch); self->pitch = pitch; + return 0; } //=========================================================================== @@ -2783,8 +2948,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetPitch) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ScaleVelocity) { - ACTION_PARAM_START(1); - ACTION_PARAM_FIXED(scale, 0); + PARAM_ACTION_PROLOGUE; + PARAM_FIXED(scale); INTBOOL was_moving = self->velx | self->vely | self->velz; @@ -2798,6 +2963,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ScaleVelocity) { CheckStopped(self); } + return 0; } //=========================================================================== @@ -2808,11 +2974,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ScaleVelocity) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeVelocity) { - ACTION_PARAM_START(4); - ACTION_PARAM_FIXED(x, 0); - ACTION_PARAM_FIXED(y, 1); - ACTION_PARAM_FIXED(z, 2); - ACTION_PARAM_INT(flags, 3); + PARAM_ACTION_PROLOGUE; + PARAM_FIXED_OPT (x) { x = 0; } + PARAM_FIXED_OPT (y) { y = 0; } + PARAM_FIXED_OPT (z) { z = 0; } + PARAM_INT_OPT (flags) { flags = 0; } INTBOOL was_moving = self->velx | self->vely | self->velz; @@ -2842,6 +3008,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeVelocity) { CheckStopped(self); } + return 0; } //=========================================================================== @@ -2852,15 +3019,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeVelocity) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetArg) { - ACTION_PARAM_START(2); - ACTION_PARAM_INT(pos, 0); - ACTION_PARAM_INT(value, 1); + PARAM_ACTION_PROLOGUE; + PARAM_INT(pos); + PARAM_INT(value); // Set the value of the specified arg if ((size_t)pos < countof(self->args)) { self->args[pos] = value; } + return 0; } //=========================================================================== @@ -2871,13 +3039,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetArg) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpecial) { - ACTION_PARAM_START(6); - ACTION_PARAM_INT(spec, 0); - ACTION_PARAM_INT(arg0, 1); - ACTION_PARAM_INT(arg1, 2); - ACTION_PARAM_INT(arg2, 3); - ACTION_PARAM_INT(arg3, 4); - ACTION_PARAM_INT(arg4, 5); + PARAM_ACTION_PROLOGUE; + PARAM_INT (spec); + PARAM_INT_OPT (arg0) { arg0 = 0; } + PARAM_INT_OPT (arg1) { arg1 = 0; } + PARAM_INT_OPT (arg2) { arg2 = 0; } + PARAM_INT_OPT (arg3) { arg3 = 0; } + PARAM_INT_OPT (arg4) { arg4 = 0; } self->special = spec; self->args[0] = arg0; @@ -2885,6 +3053,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpecial) self->args[2] = arg2; self->args[3] = arg3; self->args[4] = arg4; + return 0; } //=========================================================================== @@ -2895,15 +3064,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpecial) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserVar) { - ACTION_PARAM_START(2); - ACTION_PARAM_INT(pos, 0); - ACTION_PARAM_INT(value, 1); + PARAM_ACTION_PROLOGUE; + PARAM_INT(pos); + PARAM_INT(value); - if (pos < 0 || pos > 9) - return; + if (pos < 0 || pos >= countof(self->uservar)) + return 0; // Set the value of the specified arg self->uservar[pos] = value; + return 0; } //=========================================================================== @@ -2914,9 +3084,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserVar) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Turn) { - ACTION_PARAM_START(1); - ACTION_PARAM_ANGLE(angle, 0); + PARAM_ACTION_PROLOGUE; + PARAM_ANGLE_OPT(angle); self->angle += angle; + return 0; } //=========================================================================== @@ -2927,15 +3098,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Turn) // //=========================================================================== - void P_TranslateLineDef (line_t *ld, maplinedef_t *mld); DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LineEffect) { - ACTION_PARAM_START(2); - ACTION_PARAM_INT(special, 0); - ACTION_PARAM_INT(tag, 1); + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT(special) { special = 0; } + PARAM_INT_OPT(tag) { tag = 0; } - line_t junk; maplinedef_t oldjunk; + line_t junk; + maplinedef_t oldjunk; bool res = false; if (!(self->flags6 & MF6_LINEDONE)) // Unless already used up { @@ -2950,4 +3121,5 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LineEffect) } } ACTION_SET_RESULT(res); + return 0; } diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 8b0ed1a41..b063d98dc 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -590,7 +590,10 @@ void InitThingdef() while (*++probe != NULL) { - AFTable.Push(*(AFuncDesc *)*probe); + AFuncDesc *afunc = (AFuncDesc *)*probe; + assert(afunc->VMPointer != NULL); + *(afunc->VMPointer) = new VMNativeFunction(afunc->Function); + AFTable.Push(*afunc); } AFTable.ShrinkToFit(); qsort(&AFTable[0], AFTable.Size(), sizeof(AFTable[0]), funccmp); diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index fa2b1beec..42d1f0c04 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -924,7 +924,7 @@ static void ParseActionDef (FScanner &sc, PClass *cls) { PSymbolActionFunction *sym = new PSymbolActionFunction(funcname); sym->Arguments = args; - sym->Function = afd->Function; + sym->Function = *(afd->VMPointer); if (hasdefaults) { sym->defaultparameterindex = StateParams.Size(); diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index 82f8dd28c..a27bd48d3 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -98,7 +98,8 @@ bool DoActionSpecials(FScanner &sc, FState & state, Baggage &bag, FStateTempCall sc.ScriptError ("Too many arguments to %s", specname.GetChars()); } - state.SetAction(FindGlobalActionFunction("A_CallSpecial"), false); + //FIXME + //state.SetAction(FindGlobalActionFunction("A_CallSpecial"), false); return true; } return false; @@ -219,7 +220,6 @@ do_stop: state.sprite = GetSpriteIndex(statestring); state.Misc1 = state.Misc2 = 0; - state.ParameterIndex = 0; sc.MustGetString(); statestring = sc.String; @@ -262,7 +262,6 @@ do_stop: if (sym != NULL && sym->SymbolType == SYM_ActionFunction) { PSymbolActionFunction *afd = static_cast<PSymbolActionFunction *>(sym); - state.SetAction(afd, false); if (!afd->Arguments.IsEmpty()) { const char *params = afd->Arguments.GetChars(); @@ -278,7 +277,7 @@ do_stop: { if (!sc.CheckString("(")) { - state.ParameterIndex = afd->defaultparameterindex+1; +// state.ParameterIndex = afd->defaultparameterindex+1; goto endofstate; } } diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp index 5f2383fee..aa4af6a3d 100644 --- a/src/win32/i_main.cpp +++ b/src/win32/i_main.cpp @@ -1291,7 +1291,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE nothing, LPSTR cmdline, int n _CrtSetDbgFlag (_CrtSetDbgFlag(0) | _CRTDBG_LEAK_CHECK_DF); // Use this to break at a specific allocation number. - //_crtBreakAlloc = 5501; + //_crtBreakAlloc = 68843; #endif DoMain (hInstance); diff --git a/src/zscript/vm.h b/src/zscript/vm.h index acb4a0688..21a67188e 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -313,7 +313,7 @@ struct VMValue int i; struct { void *a; int atag; }; double f; - struct { int pad[3]; int Type; }; + struct { int pad[3]; VM_UBYTE Type; }; struct { int foo[4]; } biggest; }; @@ -784,7 +784,6 @@ public: NativeCallType NativeCall; }; - class VMParamFiller { public: @@ -845,4 +844,75 @@ void VMFillParams(VMValue *params, VMFrame *callee, int numparam); void VMDumpConstants(FILE *out, const VMScriptFunction *func); void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction *func); +// Use this in the prototype for a native function. +#define VM_ARGS VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret +#define VM_ARGS_NAMES stack, param, numparam, ret, numret + +// Use these to collect the parameters in a native function. +// variable name <x> at position <p> + +// For required parameters. +#define PARAM_INT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); int x = param[p].i; +#define PARAM_BOOL_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); bool x = !!param[p].i; +#define PARAM_NAME_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FName x = ENamedName(param[p].i); +#define PARAM_SOUND_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FSoundID x = param[p].i; +#define PARAM_COLOR_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); PalEntry x; x.d = param[p].i; +#define PARAM_FLOAT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); double x = param[p].f; +#define PARAM_FIXED_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); fixed_t x = fixed_t(param[p].f * 65536.0); +#define PARAM_ANGLE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); angle_t x = angle_t(param[p].f * (ANGLE_90 / 90.0)); +#define PARAM_STRING_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_STRING); FString x = param[p].s(); +#define PARAM_STATE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].a == NULL)); FState *x = (FState *)param[p].a; +#define PARAM_POINTER_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)param[p].a; +#define PARAM_OBJECT_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); type *x = (type *)param[p].a; +#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); PClass *x = (PClass *)param[p].a; assert(x->IsDescendantOf(RUNTIME_CLASS(base))); + +// For optional paramaters. These have dangling elses for you to fill in the default assignment. e.g.: +// PARAM_INT_OPT(0,myint) { myint = 55; } +// Just make sure to fill it in when using these macros, because the compiler isn't likely +// to give useful error messages if you don't. +#define PARAM_INT_OPT_AT(p,x) int x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x = param[p].i; } else +#define PARAM_BOOL_OPT_AT(p,x) bool x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x = !!param[p].i; } else +#define PARAM_NAME_OPT_AT(p,x) FName x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x = ENamedName(param[p].i); } else +#define PARAM_SOUND_OPT_AT(p,x) FSoundID x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x = FSoundID(param[p].i); } else +#define PARAM_COLOR_OPT_AT(p,x) PalEntry x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x.d = param[p].i; } else +#define PARAM_FLOAT_OPT_AT(p,x) double x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_FLOAT); x = param[p].f; } else +#define PARAM_FIXED_OPT_AT(p,x) fixed_t x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_FLOAT); x = fixed_t(param[p].f * 65536.0); } else +#define PARAM_ANGLE_OPT_AT(p,x) angle_t x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_FLOAT); x = angle_t(param[p].f * (ANGLE_90 / 90.0)); } else +#define PARAM_STRING_OPT_AT(p,x) FString x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_STRING); x = param[p].s(); } else +#define PARAM_STATE_OPT_AT(p,x) FState *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].a == NULL)); x = (FState *)param[p].a; } else +#define PARAM_POINTER_OPT_AT(p,x,type) type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER); x = (type *)param[p].a; } else +#define PARAM_OBJECT_OPT_AT(p,x,type) type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (type *)param[p].a; } else +#define PARAM_CLASS_OPT_AT(p,x,base) PClass *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (PClass *)param[p].a; assert(x->IsKindOf(RUNTIME_CLASS(base))); } else + +// The above, but with an automatically increasing position index. +#define PARAM_PROLOGUE int pnum = -1; + +#define PARAM_INT(x) ++pnum; PARAM_INT_AT(pnum,x) +#define PARAM_BOOL(x) ++pnum; PARAM_BOOL_AT(pnum,x) +#define PARAM_NAME(x) ++pnum; PARAM_NAME_AT(pnum,x) +#define PARAM_SOUND(x) ++pnum; PARAM_SOUND_AT(pnum,x) +#define PARAM_COLOR(x) ++pnum; PARAM_COLOR_AT(pnum,x) +#define PARAM_FLOAT(x) ++pnum; PARAM_FLOAT_AT(pnum,x) +#define PARAM_FIXED(x) ++pnum; PARAM_FIXED_AT(pnum,x) +#define PARAM_ANGLE(x) ++pnum; PARAM_ANGLE_AT(pnum,x) +#define PARAM_STRING(x) ++pnum; PARAM_STRING_AT(pnum,x) +#define PARAM_STATE(x) ++pnum; PARAM_STATE_AT(pnum,x) +#define PARAM_POINTER(x,type) ++pnum; PARAM_POINTER_AT(pnum,x,type) +#define PARAM_OBJECT(x,type) ++pnum; PARAM_OBJECT_AT(pnum,x,type) +#define PARAM_CLASS(x,base) ++pnum; PARAM_CLASS_AT(pnum,x,base) + +#define PARAM_INT_OPT(x) ++pnum; PARAM_INT_OPT_AT(pnum,x) +#define PARAM_BOOL_OPT(x) ++pnum; PARAM_BOOL_OPT_AT(pnum,x) +#define PARAM_NAME_OPT(x) ++pnum; PARAM_NAME_OPT_AT(pnum,x) +#define PARAM_SOUND_OPT(x) ++pnum; PARAM_SOUND_OPT_AT(pnum,x) +#define PARAM_COLOR_OPT(x) ++pnum; PARAM_COLOR_OPT_AT(pnum,x) +#define PARAM_FLOAT_OPT(x) ++pnum; PARAM_FLOAT_OPT_AT(pnum,x) +#define PARAM_FIXED_OPT(x) ++pnum; PARAM_FIXED_OPT_AT(pnum,x) +#define PARAM_ANGLE_OPT(x) ++pnum; PARAM_ANGLE_OPT_AT(pnum,x) +#define PARAM_STRING_OPT(x) ++pnum; PARAM_STRING_OPT_AT(pnum,x) +#define PARAM_STATE_OPT(x) ++pnum; PARAM_STATE_OPT_AT(pnum,x) +#define PARAM_POINTER_OPT(x,type) ++pnum; PARAM_POINTER_OPT_AT(pnum,x,type) +#define PARAM_OBJECT_OPT(x,type) ++pnum; PARAM_OBJECT_OPT_AT(pnum,x,type) +#define PARAM_CLASS_OPT(x,base) ++pnum; PARAM_CLASS_OPT_AT(pnum,x,base) + #endif diff --git a/src/zscript/vmexec.cpp b/src/zscript/vmexec.cpp index c05ebca92..21f897d0d 100644 --- a/src/zscript/vmexec.cpp +++ b/src/zscript/vmexec.cpp @@ -138,7 +138,7 @@ void VMSelectEngine(EVMEngine engine) // // VMFillParams // -// Takes parameters from the paramater stack and stores them in the callee's +// Takes parameters from the parameter stack and stores them in the callee's // registers. // //=========================================================================== diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 8f66780ff..0bb53fa0a 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -147,7 +147,7 @@ ACTOR Actor native //: Thinker action native A_BishopMissileWeave(); action native A_CStaffMissileSlither(); action native A_PlayerScream(); - action native A_SkullPop(class<Actor> skulltype = "BloodySkull"); + action native A_SkullPop(class<PlayerChunk> skulltype = "BloodySkull"); action native A_CheckPlayerDone(); action native A_Wander(); @@ -182,7 +182,7 @@ ACTOR Actor native //: Thinker action native A_Jump(int chance = 256, state label, ...); action native A_CustomMissile(class<Actor> missiletype, float spawnheight = 32, int spawnofs_xy = 0, float angle = 0, int flags = 0, float pitch = 0); action native A_CustomBulletAttack(float spread_xy, float spread_z, int numbullets, int damageperbullet, class<Actor> pufftype = "BulletPuff", float range = 0, bool aimfacing = false); - action native A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = "", color color2 = "", int flags = 0, bool aim = false, float maxdiff = 0, class<Actor> pufftype = "BulletPuff"); + action native A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = "", color color2 = "", int flags = 0, int aim = 0, float maxdiff = 0, class<Actor> pufftype = "BulletPuff"); action native A_JumpIfHealthLower(int health, state label); action native A_JumpIfCloser(float distance, state label); action native A_JumpIfInventory(class<Inventory> itemtype, int itemamount, state label); @@ -191,8 +191,8 @@ ACTOR Actor native //: Thinker action native A_TakeInventory(class<Inventory> itemtype, int amount = 0); action native A_SpawnItem(class<Actor> itemtype = "Unknown", float distance = 0, float zheight = 0, bool useammo = true, bool transfer_translation = false); action native A_SpawnItemEx(class<Actor> itemtype, float xofs = 0, float yofs = 0, float zofs = 0, float xvel = 0, float yvel = 0, float zvel = 0, float angle = 0, int flags = 0, int failchance = 0); - action native A_Print(string whattoprint, float time = 0, string fontname = ""); - action native A_PrintBold(string whattoprint, float time = 0, string fontname = ""); + action native A_Print(string whattoprint, float time = 0, name fontname = ""); + action native A_PrintBold(string whattoprint, float time = 0, name fontname = ""); action native A_Log(string whattoprint); action native A_SetTranslucent(float alpha, int style = 0); action native A_FadeIn(float reduce = 0.1); diff --git a/wadsrc/static/actors/shared/debris.txt b/wadsrc/static/actors/shared/debris.txt index 5d48a2217..6bb3fccdb 100644 --- a/wadsrc/static/actors/shared/debris.txt +++ b/wadsrc/static/actors/shared/debris.txt @@ -11,7 +11,7 @@ ACTOR Rock1 States { Spawn: - ROKK A 20 + ROKK A 20 A_Log("Test") Loop Death: ROKK A 10 diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt index ca73cab29..359fd51fe 100644 --- a/wadsrc/static/actors/shared/inventory.txt +++ b/wadsrc/static/actors/shared/inventory.txt @@ -10,7 +10,7 @@ ACTOR Inventory native action native A_CustomPunch(int damage, bool norandom = false, bool useammo = true, class<Actor> pufftype = "BulletPuff", float range = 0); action native A_FireBullets(float spread_xy, float spread_z, int numbullets, int damageperbullet, class<Actor> pufftype = "BulletPuff", bool useammo = true, float range = 0); action native A_FireCustomMissile(class<Actor> missiletype, float angle = 0, bool useammo = true, int spawnofs_xy = 0, float spawnheight = 0, bool aimatangle = false, float pitch = 0); - action native A_RailAttack(int damage, int spawnofs_xy = 0, int useammo = true, color color1 = "", color color2 = "", int flags = 0, float maxdiff = 0, class<Actor> pufftype = "BulletPuff"); + action native A_RailAttack(int damage, int spawnofs_xy = 0, bool useammo = true, color color1 = "", color color2 = "", int flags = 0, float maxdiff = 0, class<Actor> pufftype = "BulletPuff"); action native A_Light(int extralight); action native A_Light0(); action native A_Light1(); From 6f1bf257e980fbe8bad16c50579cb76b19fdd2c2 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sun, 14 Feb 2010 19:59:21 +0000 Subject: [PATCH 019/232] - State code now properly calls action functions and has a RET instruction. As expected, running with the checked VM can be quite slow, since it has asserts everywhere. Some other fixes were needed before the code actually worked: - A_CallSpecial needs to have its arguments cast to ints. - Some functions that set pnum/paramnum directly did not decrement it by 1. This also applies to A_Jump, though it just uses the value of paramnum instead of changing it. - Renamed pnum in the PARAM macros to paramnum, since pnum is already used in a few other places for something different, so this makes searching for it easier. This has not been tested especially thoroughly, but a first glance seems to indicate success. SVN r2163 (scripting) --- src/thingdef/thingdef.cpp | 73 +++++++++++++++--------- src/thingdef/thingdef.h | 7 ++- src/thingdef/thingdef_codeptr.cpp | 11 ++-- src/thingdef/thingdef_expression.cpp | 12 ++-- src/thingdef/thingdef_states.cpp | 8 +-- src/zscript/vm.h | 85 +++++++++++++++------------- src/zscript/vmdisasm.cpp | 2 +- src/zscript/vmexec.h | 35 +++++------- wadsrc/static/actors/actor.txt | 1 - 9 files changed, 128 insertions(+), 106 deletions(-) diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 4e526665d..b22e558d3 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -286,42 +286,59 @@ static void FinishThingdef() for (i = 0; i < StateTempCalls.Size(); ++i) { FStateTempCall *tcall = StateTempCalls[i]; - FCompileContext ctx(tcall->ActorInfo->Class, true); - for (j = 0; j < tcall->Parameters.Size(); ++j) + VMFunction *func; + + assert(tcall->Function != NULL); + if (tcall->Parameters.Size() == 0) { - tcall->Parameters[j]->Resolve(ctx); + func = tcall->Function; } - VMFunctionBuilder buildit; - // Allocate registers used to pass parameters in. - // self, stateowner, state, statecalldata (all are pointers) - buildit.Registers[REGT_POINTER].Get(4); - // Emit code for action parameters. - for (j = 0; j < tcall->Parameters.Size(); ++j) + else { - FxExpression *p = /*new FxParameter*/(tcall->Parameters[j]); - p->Emit(&buildit); - delete p; + FCompileContext ctx(tcall->ActorInfo->Class, true); + for (j = 0; j < tcall->Parameters.Size(); ++j) + { + tcall->Parameters[j]->Resolve(ctx); + } + VMFunctionBuilder buildit; + // Allocate registers used to pass parameters in. + // self, stateowner, state, statecalldata (all are pointers) + buildit.Registers[REGT_POINTER].Get(4); + // Emit code to pass the standard action function parameters. + buildit.Emit(OP_PARAM, 0, REGT_POINTER, 0); + buildit.Emit(OP_PARAM, 0, REGT_POINTER, 1); + buildit.Emit(OP_PARAM, 0, REGT_POINTER, 2); + buildit.Emit(OP_PARAM, 0, REGT_POINTER, 3); + // Emit code for action parameters. + for (j = 0; j < tcall->Parameters.Size(); ++j) + { + FxExpression *p = /*new FxParameter*/(tcall->Parameters[j]); + p->Emit(&buildit); + delete p; + } + buildit.Emit(OP_CALL_K, buildit.GetConstantAddress(tcall->Function, ATAG_OBJECT), NAP + j, 0); + buildit.Emit(OP_RET, 0, REGT_NIL, 0); + VMScriptFunction *sfunc = buildit.MakeFunction(); + sfunc->NumArgs = NAP; + func = sfunc; +#if 1 + const char *marks = "======================================================="; + char label[64]; + int labellen = mysnprintf(label, countof(label), "Function %s.States[%d] (*%d)", + tcall->ActorInfo->Class->TypeName.GetChars(), + tcall->FirstState, tcall->NumStates); + fprintf(dump, "\n%.*s %s %.*s", MAX(3, 38 - labellen / 2), marks, label, MAX(3, 38 - labellen / 2), marks); + fprintf(dump, "\nInteger regs: %-3d Float regs: %-3d Address regs: %-3d String regs: %-3d\nStack size: %d\n", + sfunc->NumRegD, sfunc->NumRegF, sfunc->NumRegA, sfunc->NumRegS, sfunc->MaxParam); + VMDumpConstants(dump, sfunc); + fprintf(dump, "\nDisassembly @ %p:\n", sfunc->Code); + VMDisasm(dump, sfunc->Code, sfunc->CodeSize, sfunc); +#endif } - buildit.Emit(OP_CALL_K, buildit.GetConstantAddress(NULL, ATAG_OBJECT), j, 0); - VMScriptFunction *func = buildit.MakeFunction(); - func->NumArgs = tcall->Parameters.Size(); for (int k = 0; k < tcall->NumStates; ++k) { tcall->ActorInfo->OwnedStates[tcall->FirstState + k].SetAction(func); } -#if 1 - const char *marks = "======================================================="; - char label[64]; - int labellen = mysnprintf(label, countof(label), "Function %s.States[%d] (*%d)", - tcall->ActorInfo->Class->TypeName.GetChars(), - tcall->FirstState, tcall->NumStates); - fprintf(dump, "\n%.*s %s %.*s", MAX(3, 38 - labellen / 2), marks, label, MAX(3, 38 - labellen / 2), marks); - fprintf(dump, "\nInteger regs: %-3d Float regs: %-3d Address regs: %-3d String regs: %-3d\nStack size: %d\n", - func->NumRegD, func->NumRegF, func->NumRegA, func->NumRegS, func->MaxParam); - VMDumpConstants(dump, func); - fprintf(dump, "\nDisassembly:\n"); - VMDisasm(dump, func->Code, func->CodeSize, func); -#endif } fclose(dump); diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index 60ff50620..4829cc306 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -111,10 +111,13 @@ public: struct FStateTempCall { + FStateTempCall() : ActorInfo(NULL), Function(NULL), FirstState(0), NumStates(0) {} + FActorInfo *ActorInfo; + VMFunction *Function; + TArray<FxExpression *> Parameters; int FirstState; int NumStates; - TArray<FxExpression *> Parameters; }; extern TDeletingArray<FStateTempCall *> StateTempCalls; @@ -386,7 +389,7 @@ struct StateCallData //#define PUSH_PARAMINFO self, stateowner, CallingState, ParameterIndex, statecall #define CALL_ACTION(name,self) { /*AF_##name(self, self, NULL, 0, NULL)*/ \ - VMValue params[5] = { self, self, NULL, VMValue(NULL, ATAG_STATE) }; \ + VMValue params[5] = { self, self, VMValue(NULL, ATAG_STATE), VMValue(NULL, ATAG_GENERIC) }; \ stack->Call(name##_VMPtr, params, countof(params), NULL, 0, NULL); \ } diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 9da7ff3b5..c12f41a52 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -452,11 +452,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Jump) PARAM_ACTION_PROLOGUE; PARAM_INT_OPT(maxchance) { maxchance = 256; } - int count = numparam - pnum; + paramnum++; // Increment paramnum to point at the first jump target + int count = numparam - paramnum; if (count > 0 && (maxchance >= 256 || pr_cajump() < maxchance)) { int jumpnum = (count == 1 ? 0 : (pr_cajump() % count)); - PARAM_STATE_AT(pnum + jumpnum, jumpto); + PARAM_STATE_AT(paramnum + jumpnum, jumpto); ACTION_JUMP(jumpto); } ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! @@ -529,7 +530,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfCloser) //========================================================================== void DoJumpIfInventory(AActor *owner, AActor *self, StateCallData *statecall, FState *callingstate, VMValue *param, int numparam) { - int pnum = NAP; + int paramnum = NAP-1; PARAM_CLASS (itemtype, AInventory); PARAM_INT (itemamount); PARAM_STATE (label); @@ -1314,7 +1315,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) static void DoGiveInventory(AActor *receiver, StateCallData *statecall, VM_ARGS) { - int pnum = NAP; + int paramnum = NAP-1; PARAM_CLASS (mi, AInventory); PARAM_INT_OPT (amount) { amount = 1; } @@ -1381,7 +1382,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToTarget) void DoTakeInventory(AActor *receiver, StateCallData *statecall, VM_ARGS) { - int pnum = NAP; + int paramnum = NAP-1; PARAM_CLASS (itemtype, AInventory); PARAM_INT_OPT (amount) { amount = 0; } diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 7b32a132f..5167bba6a 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3735,7 +3735,7 @@ int DecoNameToClass(VMFrameStack *stack, VMValue *param, int numparam, VMReturn Printf("class '%s' is not compatible with '%s'", clsname.GetChars(), desttype->TypeName.GetChars()); cls = NULL; } - ret->SetPointer(const_cast<PClass *>(cls)); + ret->SetPointer(const_cast<PClass *>(cls), ATAG_OBJECT); return 1; } @@ -3923,15 +3923,15 @@ int DecoFindMultiNameState(VMFrameStack *stack, VMValue *param, int numparam, VM { assert(numparam > 1); assert(numret == 1); - assert(param[0].Type == REGT_POINTER); assert(ret->RegType == REGT_POINTER); FName *names = (FName *)alloca((numparam - 1) * sizeof(FName)); for (int i = 1; i < numparam; ++i) { - names[i - 1] = ENamedName(param[i].i); + PARAM_NAME_AT(i, zaname); + names[i - 1] = zaname; } - AActor *self = reinterpret_cast<AActor *>(param[0].a); + PARAM_OBJECT_AT(0, self, AActor); FState *state = self->GetClass()->ActorInfo->FindState(numparam - 1, names); if (state == NULL) { @@ -3944,14 +3944,14 @@ int DecoFindMultiNameState(VMFrameStack *stack, VMValue *param, int numparam, VM } Printf("' not found in %s\n", self->GetClass()->TypeName.GetChars()); } - ret->SetPointer(state); + ret->SetPointer(state, ATAG_STATE); return 1; } ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build) { ExpEmit dest(build, REGT_POINTER); - build->Emit(OP_PARAM, 0, REGT_POINTER, 0); // pass self + build->Emit(OP_PARAM, 0, REGT_POINTER, 1); // pass stateowner for (unsigned i = 0; i < names.Size(); ++i) { EmitConstantInt(build, names[i]); diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index a27bd48d3..208581b51 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -81,7 +81,7 @@ bool DoActionSpecials(FScanner &sc, FState & state, Baggage &bag, FStateTempCall { for (i = 0; i < 5;) { - tcall->Parameters.Push(new FxParameter(ParseExpression(sc, bag.Info->Class))); + tcall->Parameters.Push(new FxParameter(new FxIntCast(ParseExpression(sc, bag.Info->Class)))); i++; if (!sc.CheckToken (',')) break; } @@ -98,8 +98,7 @@ bool DoActionSpecials(FScanner &sc, FState & state, Baggage &bag, FStateTempCall sc.ScriptError ("Too many arguments to %s", specname.GetChars()); } - //FIXME - //state.SetAction(FindGlobalActionFunction("A_CallSpecial"), false); + tcall->Function = FindGlobalActionFunction("A_CallSpecial")->Function; return true; } return false; @@ -262,6 +261,7 @@ do_stop: if (sym != NULL && sym->SymbolType == SYM_ActionFunction) { PSymbolActionFunction *afd = static_cast<PSymbolActionFunction *>(sym); + tcall->Function = afd->Function; if (!afd->Arguments.IsEmpty()) { const char *params = afd->Arguments.GetChars(); @@ -374,7 +374,7 @@ endofstate: sc.ScriptError ("Invalid frame character string '%s'", statestring.GetChars()); count = -count; } - if (tcall->Parameters.Size() != 0) + if (tcall->Function != NULL) { tcall->ActorInfo = actor; tcall->FirstState = bag.statedef.GetStateCount() - count; diff --git a/src/zscript/vm.h b/src/zscript/vm.h index 21a67188e..72e2141d5 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -251,54 +251,63 @@ extern const VMOpInfo OpInfo[NUM_OPS]; struct VMReturn { void *Location; - VM_SHALF RegNum; // Used to find ObjFlag index for pointers; set negative if the caller is native code and doesn't care + VM_SHALF TagOfs; // for pointers: Offset from Location to ATag; set to 0 if the caller is native code and doesn't care VM_UBYTE RegType; // Same as VMParam RegType, except REGT_KONST is invalid; only used by asserts void SetInt(int val) { + assert(RegType == REGT_INT); *(int *)Location = val; } void SetFloat(double val) { + assert(RegType == REGT_FLOAT); *(double *)Location = val; } void SetVector(const double val[3]) - { + { + //assert(RegType == REGT_FLOAT); ((double *)Location)[0] = val[0]; ((double *)Location)[1] = val[1]; ((double *)Location)[2] = val[2]; } void SetString(const FString &val) { + assert(RegType == REGT_STRING); *(FString *)Location = val; } - void SetPointer(void *val) + void SetPointer(void *val, int tag) { + assert(RegType == REGT_POINTER); *(void **)Location = val; + if (TagOfs != 0) + { + *((VM_ATAG *)Location + TagOfs) = tag; + } } void IntAt(int *loc) { Location = loc; - RegNum = -1; + TagOfs = 0; RegType = REGT_INT; } void FloatAt(double *loc) { Location = loc; - RegNum = -1; + TagOfs = 0; RegType = REGT_FLOAT; } void StringAt(FString *loc) { Location = loc; - RegNum = -1; + TagOfs = 0; RegType = REGT_STRING; } void PointerAt(void **loc) { Location = loc; - RegNum = -1; + TagOfs = 0; RegType = REGT_POINTER; } }; @@ -863,8 +872,8 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction #define PARAM_STRING_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_STRING); FString x = param[p].s(); #define PARAM_STATE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].a == NULL)); FState *x = (FState *)param[p].a; #define PARAM_POINTER_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)param[p].a; -#define PARAM_OBJECT_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); type *x = (type *)param[p].a; -#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); PClass *x = (PClass *)param[p].a; assert(x->IsDescendantOf(RUNTIME_CLASS(base))); +#define PARAM_OBJECT_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); type *x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); +#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); PClass *x = (PClass *)param[p].a; assert(x != NULL && x->IsDescendantOf(RUNTIME_CLASS(base))); // For optional paramaters. These have dangling elses for you to fill in the default assignment. e.g.: // PARAM_INT_OPT(0,myint) { myint = 55; } @@ -881,38 +890,38 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction #define PARAM_STRING_OPT_AT(p,x) FString x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_STRING); x = param[p].s(); } else #define PARAM_STATE_OPT_AT(p,x) FState *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].a == NULL)); x = (FState *)param[p].a; } else #define PARAM_POINTER_OPT_AT(p,x,type) type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER); x = (type *)param[p].a; } else -#define PARAM_OBJECT_OPT_AT(p,x,type) type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (type *)param[p].a; } else -#define PARAM_CLASS_OPT_AT(p,x,base) PClass *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (PClass *)param[p].a; assert(x->IsKindOf(RUNTIME_CLASS(base))); } else +#define PARAM_OBJECT_OPT_AT(p,x,type) type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); } else +#define PARAM_CLASS_OPT_AT(p,x,base) PClass *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (PClass *)param[p].a; assert(x != NULL && x->IsDescendantOf(RUNTIME_CLASS(base))); } else // The above, but with an automatically increasing position index. -#define PARAM_PROLOGUE int pnum = -1; +#define PARAM_PROLOGUE int paramnum = -1; -#define PARAM_INT(x) ++pnum; PARAM_INT_AT(pnum,x) -#define PARAM_BOOL(x) ++pnum; PARAM_BOOL_AT(pnum,x) -#define PARAM_NAME(x) ++pnum; PARAM_NAME_AT(pnum,x) -#define PARAM_SOUND(x) ++pnum; PARAM_SOUND_AT(pnum,x) -#define PARAM_COLOR(x) ++pnum; PARAM_COLOR_AT(pnum,x) -#define PARAM_FLOAT(x) ++pnum; PARAM_FLOAT_AT(pnum,x) -#define PARAM_FIXED(x) ++pnum; PARAM_FIXED_AT(pnum,x) -#define PARAM_ANGLE(x) ++pnum; PARAM_ANGLE_AT(pnum,x) -#define PARAM_STRING(x) ++pnum; PARAM_STRING_AT(pnum,x) -#define PARAM_STATE(x) ++pnum; PARAM_STATE_AT(pnum,x) -#define PARAM_POINTER(x,type) ++pnum; PARAM_POINTER_AT(pnum,x,type) -#define PARAM_OBJECT(x,type) ++pnum; PARAM_OBJECT_AT(pnum,x,type) -#define PARAM_CLASS(x,base) ++pnum; PARAM_CLASS_AT(pnum,x,base) +#define PARAM_INT(x) ++paramnum; PARAM_INT_AT(paramnum,x) +#define PARAM_BOOL(x) ++paramnum; PARAM_BOOL_AT(paramnum,x) +#define PARAM_NAME(x) ++paramnum; PARAM_NAME_AT(paramnum,x) +#define PARAM_SOUND(x) ++paramnum; PARAM_SOUND_AT(paramnum,x) +#define PARAM_COLOR(x) ++paramnum; PARAM_COLOR_AT(paramnum,x) +#define PARAM_FLOAT(x) ++paramnum; PARAM_FLOAT_AT(paramnum,x) +#define PARAM_FIXED(x) ++paramnum; PARAM_FIXED_AT(paramnum,x) +#define PARAM_ANGLE(x) ++paramnum; PARAM_ANGLE_AT(paramnum,x) +#define PARAM_STRING(x) ++paramnum; PARAM_STRING_AT(paramnum,x) +#define PARAM_STATE(x) ++paramnum; PARAM_STATE_AT(paramnum,x) +#define PARAM_POINTER(x,type) ++paramnum; PARAM_POINTER_AT(paramnum,x,type) +#define PARAM_OBJECT(x,type) ++paramnum; PARAM_OBJECT_AT(paramnum,x,type) +#define PARAM_CLASS(x,base) ++paramnum; PARAM_CLASS_AT(paramnum,x,base) -#define PARAM_INT_OPT(x) ++pnum; PARAM_INT_OPT_AT(pnum,x) -#define PARAM_BOOL_OPT(x) ++pnum; PARAM_BOOL_OPT_AT(pnum,x) -#define PARAM_NAME_OPT(x) ++pnum; PARAM_NAME_OPT_AT(pnum,x) -#define PARAM_SOUND_OPT(x) ++pnum; PARAM_SOUND_OPT_AT(pnum,x) -#define PARAM_COLOR_OPT(x) ++pnum; PARAM_COLOR_OPT_AT(pnum,x) -#define PARAM_FLOAT_OPT(x) ++pnum; PARAM_FLOAT_OPT_AT(pnum,x) -#define PARAM_FIXED_OPT(x) ++pnum; PARAM_FIXED_OPT_AT(pnum,x) -#define PARAM_ANGLE_OPT(x) ++pnum; PARAM_ANGLE_OPT_AT(pnum,x) -#define PARAM_STRING_OPT(x) ++pnum; PARAM_STRING_OPT_AT(pnum,x) -#define PARAM_STATE_OPT(x) ++pnum; PARAM_STATE_OPT_AT(pnum,x) -#define PARAM_POINTER_OPT(x,type) ++pnum; PARAM_POINTER_OPT_AT(pnum,x,type) -#define PARAM_OBJECT_OPT(x,type) ++pnum; PARAM_OBJECT_OPT_AT(pnum,x,type) -#define PARAM_CLASS_OPT(x,base) ++pnum; PARAM_CLASS_OPT_AT(pnum,x,base) +#define PARAM_INT_OPT(x) ++paramnum; PARAM_INT_OPT_AT(paramnum,x) +#define PARAM_BOOL_OPT(x) ++paramnum; PARAM_BOOL_OPT_AT(paramnum,x) +#define PARAM_NAME_OPT(x) ++paramnum; PARAM_NAME_OPT_AT(paramnum,x) +#define PARAM_SOUND_OPT(x) ++paramnum; PARAM_SOUND_OPT_AT(paramnum,x) +#define PARAM_COLOR_OPT(x) ++paramnum; PARAM_COLOR_OPT_AT(paramnum,x) +#define PARAM_FLOAT_OPT(x) ++paramnum; PARAM_FLOAT_OPT_AT(paramnum,x) +#define PARAM_FIXED_OPT(x) ++paramnum; PARAM_FIXED_OPT_AT(paramnum,x) +#define PARAM_ANGLE_OPT(x) ++paramnum; PARAM_ANGLE_OPT_AT(paramnum,x) +#define PARAM_STRING_OPT(x) ++paramnum; PARAM_STRING_OPT_AT(paramnum,x) +#define PARAM_STATE_OPT(x) ++paramnum; PARAM_STATE_OPT_AT(paramnum,x) +#define PARAM_POINTER_OPT(x,type) ++paramnum; PARAM_POINTER_OPT_AT(paramnum,x,type) +#define PARAM_OBJECT_OPT(x,type) ++paramnum; PARAM_OBJECT_OPT_AT(paramnum,x,type) +#define PARAM_CLASS_OPT(x,base) ++paramnum; PARAM_CLASS_OPT_AT(paramnum,x,base) #endif diff --git a/src/zscript/vmdisasm.cpp b/src/zscript/vmdisasm.cpp index 9175cc096..5e7d4e0cc 100644 --- a/src/zscript/vmdisasm.cpp +++ b/src/zscript/vmdisasm.cpp @@ -155,7 +155,7 @@ void VMDumpConstants(FILE *out, const VMScriptFunction *func) { for (j = 0, k = i; j < 4 && k < func->NumKonstA; j++, k += kk) { - mysnprintf(tmp, countof(tmp), "%3d. %p", k, func->KonstA[k]); + mysnprintf(tmp, countof(tmp), "%3d. %p:%d", k, func->KonstA[k], func->KonstATags()[k]); printf_wrapper(out, "%-20s", tmp); } printf_wrapper(out, "\n"); diff --git a/src/zscript/vmexec.h b/src/zscript/vmexec.h index 07809909b..e9847946f 100644 --- a/src/zscript/vmexec.h +++ b/src/zscript/vmexec.h @@ -1384,7 +1384,7 @@ static void DoCast(const VMRegisters ®, const VMFrame *f, int a, int b, int c static void FillReturns(const VMRegisters ®, VMFrame *frame, VMReturn *returns, const VMOP *retval, int numret) { - int i, type, num; + int i, type, regnum; VMReturn *ret; assert(REGT_INT == 0 && REGT_FLOAT == 1 && REGT_STRING == 2 && REGT_POINTER == 3); @@ -1392,33 +1392,35 @@ static void FillReturns(const VMRegisters ®, VMFrame *frame, VMReturn *return for (i = 0, ret = returns; i < numret; ++i, ++ret, ++retval) { assert(retval->op == OP_RESULT); // opcode + ret->TagOfs = 0; ret->RegType = type = retval->b; - ret->RegNum = num = retval->c; + regnum = retval->c; assert(!(type & REGT_KONST)); type &= REGT_TYPE; if (type < REGT_STRING) { if (type == REGT_INT) { - assert(num < frame->NumRegD); - ret->Location = ®.d[num]; + assert(regnum < frame->NumRegD); + ret->Location = ®.d[regnum]; } else // type == REGT_FLOAT { - assert(num < frame->NumRegF); - ret->Location = ®.f[num]; + assert(regnum < frame->NumRegF); + ret->Location = ®.f[regnum]; } } else if (type == REGT_STRING) { - assert(num < frame->NumRegS); - ret->Location = ®.s[num]; + assert(regnum < frame->NumRegS); + ret->Location = ®.s[regnum]; } else { assert(type == REGT_POINTER); - assert(num < frame->NumRegA); - ret->Location = ®.a[num]; + assert(regnum < frame->NumRegA); + ret->Location = ®.a[regnum]; + ret->TagOfs = (VM_SHALF)(&frame->GetRegATag()[regnum] - (VM_ATAG *)ret->Location); } } } @@ -1434,7 +1436,6 @@ static void FillReturns(const VMRegisters ®, VMFrame *frame, VMReturn *return static void SetReturn(const VMRegisters ®, VMFrame *frame, VMReturn *ret, VM_UBYTE regtype, int regnum) { const void *src; - VM_ATAG atag; VMScriptFunction *func = static_cast<VMScriptFunction *>(frame->Func); assert(func != NULL && !func->Native); @@ -1498,20 +1499,12 @@ static void SetReturn(const VMRegisters ®, VMFrame *frame, VMReturn *ret, VM_ if (regtype & REGT_KONST) { assert(regnum < func->NumKonstA); - ret->SetPointer(func->KonstA[regnum].v); - atag = func->KonstATags()[regnum]; + ret->SetPointer(func->KonstA[regnum].v, func->KonstATags()[regnum]); } else { assert(regnum < frame->NumRegA); - ret->SetPointer(reg.a[regnum]); - atag = reg.atag[regnum]; - } - if (ret->RegNum >= 0) - { - VMFrame *parent = frame->ParentFrame; - assert(parent != NULL); - parent->GetRegATag()[ret->RegNum] = atag; + ret->SetPointer(reg.a[regnum], reg.atag[regnum]); } break; } diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 0bb53fa0a..568ecf262 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -26,7 +26,6 @@ ACTOR Actor native //: Thinker native fixed_t alpha; native angle_t angle; native int args[5]; - native int uservar[10]; native fixed_t ceilingz; native fixed_t floorz; native int health; From 873ece3d559d6ccc3edcebc9ba381678b6ecb814 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sun, 14 Feb 2010 20:16:05 +0000 Subject: [PATCH 020/232] - Added a vmengine console command to switch the VM engine at runtime. SVN r2164 (scripting) --- src/c_cmds.cpp | 28 ++++++++++++++++++++++++++++ src/zscript/vmexec.cpp | 9 +++++++++ 2 files changed, 37 insertions(+) diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index ed27e2d27..c61c98f8e 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -923,3 +923,31 @@ CCMD(nextsecret) Printf("no next secret map!\n"); } } + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- +CCMD(vmengine) +{ + if (argv.argc() == 2) + { + if (stricmp(argv[1], "default") == 0) + { + VMSelectEngine(VMEngine_Default); + return; + } + else if (stricmp(argv[1], "checked") == 0) + { + VMSelectEngine(VMEngine_Checked); + return; + } + else if (stricmp(argv[1], "unchecked") == 0) + { + VMSelectEngine(VMEngine_Unchecked); + return; + } + } + Printf("Usage: vmengine <default|checked|unchecked>\n"); +} diff --git a/src/zscript/vmexec.cpp b/src/zscript/vmexec.cpp index 21f897d0d..8ad349cf7 100644 --- a/src/zscript/vmexec.cpp +++ b/src/zscript/vmexec.cpp @@ -114,6 +114,15 @@ VMExec_Checked::Exec #endif ; +//=========================================================================== +// +// VMSelectEngine +// +// Selects the VM engine, either checked or unchecked. Default will decide +// based on the NDEBUG preprocessor definition. +// +//=========================================================================== + void VMSelectEngine(EVMEngine engine) { switch (engine) From ec364c53c10e44065e7d89773a6183d343665670 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sun, 21 Feb 2010 04:33:08 +0000 Subject: [PATCH 021/232] - Update Lemon to the latest SQLite CVS versions: * lemon.c @ 1.69 ; lempar.c @ 1.45 SVN r2172 (scripting) --- tools/lemon/lemon.c | 290 ++++++++++++++++++++++++++----------------- tools/lemon/lempar.c | 127 ++++++++++++++----- 2 files changed, 276 insertions(+), 141 deletions(-) diff --git a/tools/lemon/lemon.c b/tools/lemon/lemon.c index f4a08f789..7fd95eb2d 100644 --- a/tools/lemon/lemon.c +++ b/tools/lemon/lemon.c @@ -6,9 +6,9 @@ ** ** The author of this program disclaims copyright. ** -** This file is based on version 1.43 of lemon.c from the SQLite -** source tree, with modifications to make it work nicer when run -** by Developer Studio. +** This file is based on version 1.69 of lemon.c from the SQLite +** CVS, with modifications to make it work nicer when run +** from Developer Studio. */ #include <stdio.h> #include <stdarg.h> @@ -40,6 +40,13 @@ extern int access(); static void *msort(void *list, void *next, int (*cmp)()); +/* +** Compilers are getting increasingly pedantic about type conversions +** as C evolves ever closer to Ada.... To work around the latest problems +** we have to define the following variant of strlen(). +*/ +#define lemonStrlen(X) ((int)strlen(X)) + /******** From the file "action.h" *************************************/ static struct action *Action_new(void); static struct action *Action_sort(struct action *); @@ -133,13 +140,13 @@ struct symbol { RIGHT, NONE, UNK - } assoc; /* Associativity if predecence is defined */ + } assoc; /* Associativity if precedence is defined */ char *firstset; /* First-set for all rules of this symbol */ Boolean lambda; /* True if NT and can generate an empty string */ int useCnt; /* Number of times used */ char *destructor; /* Code which executes whenever this symbol is ** popped from the stack during error processing */ - int destructorln; /* Line number of destructor code */ + int destLineno; /* Line number for start of destructor */ char *datatype; /* The data type of information held by this ** object. Only used if type==NONTERMINAL */ int dtnum; /* The data type number. In the parser, the value @@ -217,7 +224,7 @@ struct action { struct state { struct config *bp; /* The basis configurations for this state */ struct config *cfp; /* All configurations in this set */ - int statenum; /* Sequencial number for this state */ + int statenum; /* Sequential number for this state */ struct action *ap; /* Array of actions for this state */ int nTknAct, nNtAct; /* Number of actions on terminals and nonterminals */ int iTknOfst, iNtOfst; /* yy_action[] offset for terminals and nonterms */ @@ -255,28 +262,21 @@ struct lemon { char *start; /* Name of the start symbol for the grammar */ char *stacksize; /* Size of the parser stack */ char *include; /* Code to put at the start of the C file */ - int includeln; /* Line number for start of include code */ char *error; /* Code to execute when an error is seen */ - int errorln; /* Line number for start of error code */ char *overflow; /* Code to execute on a stack overflow */ - int overflowln; /* Line number for start of overflow code */ char *failure; /* Code to execute on parser failure */ - int failureln; /* Line number for start of failure code */ char *accept; /* Code to execute when the parser excepts */ - int acceptln; /* Line number for the start of accept code */ char *extracode; /* Code appended to the generated file */ - int extracodeln; /* Line number for the start of the extra code */ char *tokendest; /* Code to execute to destroy token data */ - int tokendestln; /* Line number for token destroyer code */ char *vardest; /* Code for the default non-terminal destructor */ - int vardestln; /* Line number for default non-term destructor code*/ char *filename; /* Name of the input file */ char *outname; /* Name of the current output file */ char *tokenprefix; /* A prefix added to token names in the .h file */ int nconflict; /* Number of parsing conflicts */ int tablesize; /* Size of the parse tables */ int basisflag; /* Print only basis configurations */ - int has_fallback; /* True if any %fallback is seen in the grammer */ + int has_fallback; /* True if any %fallback is seen in the grammar */ + int nolinenosflag; /* True if #line statements should not be printed */ char *argv0; /* Name of the program */ }; @@ -997,7 +997,7 @@ struct lemon *lemp; } /* Resolve a conflict between the two given actions. If the -** conflict can't be resolve, return non-zero. +** conflict can't be resolved, return non-zero. ** ** NO LONGER TRUE: ** To resolve a conflict, first look to see if either action @@ -1344,13 +1344,13 @@ void ErrorMsg(const char *filename, int lineno, const char *format, ...){ sprintf(prefix,"%.*s: ",PREFIXLIMIT-10,filename); } #endif - prefixsize = strlen(prefix); + prefixsize = lemonStrlen(prefix); availablewidth = LINEWIDTH - prefixsize; /* Generate the error message */ vsprintf(errmsg,format,ap); va_end(ap); - errmsgsize = strlen(errmsg); + errmsgsize = lemonStrlen(errmsg); /* Remove trailing '\n's from the error message. */ while( errmsgsize>0 && errmsg[errmsgsize-1]=='\n' ){ errmsg[--errmsgsize] = 0; @@ -1394,7 +1394,7 @@ static void handle_D_option(char *z){ exit(1); } paz = &azDefine[nDefine-1]; - *paz = malloc( strlen(z)+1 ); + *paz = malloc( lemonStrlen(z)+1 ); if( *paz==0 ){ fprintf(stderr,"out of memory\n"); exit(1); @@ -1417,12 +1417,14 @@ char **argv; static int quiet = 0; static int statistics = 0; static int mhflag = 0; + static int nolinenosflag = 0; static struct s_options options[] = { {OPT_FLAG, "b", (char*)&basisflag, "Print only the basis in report."}, {OPT_FLAG, "c", (char*)&compress, "Don't compress the action table."}, {OPT_FSTR, "D", (char*)handle_D_option, "Define an %ifdef macro."}, {OPT_FLAG, "g", (char*)&rpflag, "Print grammar without actions."}, - {OPT_FLAG, "m", (char*)&mhflag, "Output a makeheaders compatible file"}, + {OPT_FLAG, "m", (char*)&mhflag, "Output a makeheaders compatible file."}, + {OPT_FLAG, "l", (char*)&nolinenosflag, "Do not print #line statements."}, {OPT_FLAG, "q", (char*)&quiet, "(Quiet) Don't print the report file."}, {OPT_FLAG, "s", (char*)&statistics, "Print parser stats to standard output."}, @@ -1451,6 +1453,7 @@ char **argv; lem.argv0 = argv[0]; lem.filename = OptArg(0); lem.basisflag = basisflag; + lem.nolinenosflag = nolinenosflag; Symbol_new("$"); lem.errsym = Symbol_new("error"); lem.errsym->useCnt = 0; @@ -1666,10 +1669,10 @@ FILE *err; int i; size_t spcnt; if( argv[0] ) fprintf(err,"%s",argv[0]); - spcnt = strlen(argv[0]) + 1; + spcnt = lemonStrlen(argv[0]) + 1; for(i=1; i<n && argv[i]; i++){ fprintf(err," %s",argv[i]); - spcnt += strlen(argv[i])+1; + spcnt += lemonStrlen(argv[i])+1; } spcnt += k; for(; argv[i]; i++) fprintf(err," %s",argv[i]); @@ -1714,7 +1717,7 @@ FILE *err; int errcnt = 0; int j; for(j=0; op[j].label; j++){ - if( strncmp(&argv[i][1],op[j].label,strlen(op[j].label))==0 ) break; + if( strncmp(&argv[i][1],op[j].label,lemonStrlen(op[j].label))==0 ) break; } v = argv[i][0]=='-' ? 1 : 0; if( op[j].label==0 ){ @@ -1891,7 +1894,7 @@ void OptPrint(){ size_t max, len; max = 0; for(i=0; op[i].label; i++){ - len = strlen(op[i].label) + 1; + len = lemonStrlen(op[i].label) + 1; switch( op[i].type ){ case OPT_FLAG: case OPT_FFLAG: @@ -1920,17 +1923,17 @@ void OptPrint(){ case OPT_INT: case OPT_FINT: fprintf(errstream," %s=<integer>%*s %s\n",op[i].label, - (int)(max-strlen(op[i].label)-9),"",op[i].message); + (int)(max-lemonStrlen(op[i].label)-9),"",op[i].message); break; case OPT_DBL: case OPT_FDBL: fprintf(errstream," %s=<real>%*s %s\n",op[i].label, - (int)(max-strlen(op[i].label)-6),"",op[i].message); + (int)(max-lemonStrlen(op[i].label)-6),"",op[i].message); break; case OPT_STR: case OPT_FSTR: fprintf(errstream," %s=<string>%*s %s\n",op[i].label, - (int)(max-strlen(op[i].label)-8),"",op[i].message); + (int)(max-lemonStrlen(op[i].label)-8),"",op[i].message); break; } } @@ -1978,7 +1981,8 @@ struct pstate { struct rule *prevrule; /* Previous rule parsed */ char *declkeyword; /* Keyword of a declaration */ char **declargslot; /* Where the declaration argument should be put */ - int *decllnslot; /* Where the declaration linenumber is put */ + int insertLineMacro; /* Add #line before declaration insert */ + int *decllinenoslot; /* Where to write declaration line number */ enum e_assoc declassoc; /* Assign this association to decl arguments */ int preccounter; /* Assign this precedence to decl arguments */ struct rule *firstrule; /* Pointer to first rule in the grammar */ @@ -2013,7 +2017,7 @@ struct pstate *psp; }else if( x[0]=='{' ){ if( psp->prevrule==0 ){ ErrorMsg(psp->filename,psp->tokenlineno, -"There is not prior rule opon which to attach the code \ +"There is no prior rule upon which to attach the code \ fragment which begins on this line."); psp->errorcnt++; }else if( psp->prevrule->code!=0 ){ @@ -2211,46 +2215,46 @@ to follow the previous rule."); if( isalpha(x[0]) ){ psp->declkeyword = x; psp->declargslot = 0; - psp->decllnslot = 0; + psp->decllinenoslot = 0; + psp->insertLineMacro = 1; psp->state = WAITING_FOR_DECL_ARG; if( strcmp(x,"name")==0 ){ psp->declargslot = &(psp->gp->name); + psp->insertLineMacro = 0; }else if( strcmp(x,"include")==0 ){ psp->declargslot = &(psp->gp->include); - psp->decllnslot = &psp->gp->includeln; }else if( strcmp(x,"code")==0 ){ psp->declargslot = &(psp->gp->extracode); - psp->decllnslot = &psp->gp->extracodeln; }else if( strcmp(x,"token_destructor")==0 ){ psp->declargslot = &psp->gp->tokendest; - psp->decllnslot = &psp->gp->tokendestln; }else if( strcmp(x,"default_destructor")==0 ){ psp->declargslot = &psp->gp->vardest; - psp->decllnslot = &psp->gp->vardestln; }else if( strcmp(x,"token_prefix")==0 ){ psp->declargslot = &psp->gp->tokenprefix; + psp->insertLineMacro = 0; }else if( strcmp(x,"syntax_error")==0 ){ psp->declargslot = &(psp->gp->error); - psp->decllnslot = &psp->gp->errorln; }else if( strcmp(x,"parse_accept")==0 ){ psp->declargslot = &(psp->gp->accept); - psp->decllnslot = &psp->gp->acceptln; }else if( strcmp(x,"parse_failure")==0 ){ psp->declargslot = &(psp->gp->failure); - psp->decllnslot = &psp->gp->failureln; }else if( strcmp(x,"stack_overflow")==0 ){ psp->declargslot = &(psp->gp->overflow); - psp->decllnslot = &psp->gp->overflowln; }else if( strcmp(x,"extra_argument")==0 ){ psp->declargslot = &(psp->gp->arg); + psp->insertLineMacro = 0; }else if( strcmp(x,"token_type")==0 ){ psp->declargslot = &(psp->gp->tokentype); + psp->insertLineMacro = 0; }else if( strcmp(x,"default_type")==0 ){ psp->declargslot = &(psp->gp->vartype); + psp->insertLineMacro = 0; }else if( strcmp(x,"stack_size")==0 ){ psp->declargslot = &(psp->gp->stacksize); + psp->insertLineMacro = 0; }else if( strcmp(x,"start_symbol")==0 ){ psp->declargslot = &(psp->gp->start); + psp->insertLineMacro = 0; }else if( strcmp(x,"left")==0 ){ psp->preccounter++; psp->declassoc = LEFT; @@ -2294,7 +2298,8 @@ to follow the previous rule."); }else{ struct symbol *sp = Symbol_new(x); psp->declargslot = &sp->destructor; - psp->decllnslot = &sp->destructorln; + psp->decllinenoslot = &sp->destLineno; + psp->insertLineMacro = 1; psp->state = WAITING_FOR_DECL_ARG; } break; @@ -2307,7 +2312,7 @@ to follow the previous rule."); }else{ struct symbol *sp = Symbol_new(x); psp->declargslot = &sp->datatype; - psp->decllnslot = 0; + psp->insertLineMacro = 0; psp->state = WAITING_FOR_DECL_ARG; } break; @@ -2332,18 +2337,56 @@ to follow the previous rule."); } break; case WAITING_FOR_DECL_ARG: - if( (x[0]=='{' || x[0]=='\"' || isalnum(x[0])) ){ - if( *(psp->declargslot)!=0 ){ - ErrorMsg(psp->filename,psp->tokenlineno, - "The argument \"%s\" to declaration \"%%%s\" is not the first.", - x[0]=='\"' ? &x[1] : x,psp->declkeyword); - psp->errorcnt++; - psp->state = RESYNC_AFTER_DECL_ERROR; - }else{ - *(psp->declargslot) = (x[0]=='\"' || x[0]=='{') ? &x[1] : x; - if( psp->decllnslot ) *psp->decllnslot = psp->tokenlineno; - psp->state = WAITING_FOR_DECL_OR_RULE; - } + if( x[0]=='{' || x[0]=='\"' || isalnum(x[0]) ){ + char *zOld, *zNew, *zBuf, *z; + int nOld, n, nLine, nNew, nBack; + int addLineMacro; + char zLine[50]; + zNew = x; + if( zNew[0]=='"' || zNew[0]=='{' ) zNew++; + nNew = lemonStrlen(zNew); + if( *psp->declargslot ){ + zOld = *psp->declargslot; + }else{ + zOld = ""; + } + nOld = lemonStrlen(zOld); + n = nOld + nNew + 20; + addLineMacro = !psp->gp->nolinenosflag && psp->insertLineMacro && + (psp->decllinenoslot==0 || psp->decllinenoslot[0]!=0); + if( addLineMacro ){ + for(z=psp->filename, nBack=0; *z; z++){ + if( *z=='\\' ) nBack++; + } + sprintf(zLine, "#line %d ", psp->tokenlineno); + nLine = lemonStrlen(zLine); + n += nLine + lemonStrlen(psp->filename) + nBack; + } + *psp->declargslot = zBuf = realloc(*psp->declargslot, n); + zBuf += nOld; + if( addLineMacro ){ + if( nOld && zBuf[-1]!='\n' ){ + *(zBuf++) = '\n'; + } + memcpy(zBuf, zLine, nLine); + zBuf += nLine; + *(zBuf++) = '"'; + for(z=psp->filename; *z; z++){ + if( *z=='\\' ){ + *(zBuf++) = '\\'; + } + *(zBuf++) = *z; + } + *(zBuf++) = '"'; + *(zBuf++) = '\n'; + } + if( psp->decllinenoslot && psp->decllinenoslot[0]==0 ){ + psp->decllinenoslot[0] = psp->tokenlineno; + } + memcpy(zBuf, zNew, nNew); + zBuf += nNew; + *zBuf = 0; + psp->state = WAITING_FOR_DECL_OR_RULE; }else{ ErrorMsg(psp->filename,psp->tokenlineno, "Illegal argument to %%%s: %s",psp->declkeyword,x); @@ -2400,7 +2443,7 @@ to follow the previous rule."); } } -/* Run the proprocessor over the input file text. The global variables +/* Run the preprocessor over the input file text. The global variables ** azDefine[0] through azDefine[nDefine-1] contains the names of all defined ** macros. This routine looks for "%ifdef" and "%ifndef" and "%endif" and ** comments them out. Text in between is also commented out as appropriate. @@ -2431,7 +2474,7 @@ static void preprocess_input(char *z){ for(n=0; z[j+n] && !isspace(z[j+n]); n++){} exclude = 1; for(k=0; k<nDefine; k++){ - if( strncmp(azDefine[k],&z[j],n)==0 && strlen(azDefine[k])==n ){ + if( strncmp(azDefine[k],&z[j],n)==0 && lemonStrlen(azDefine[k])==n ){ exclude = 0; break; } @@ -2703,7 +2746,7 @@ char *suffix; char *name; char *cp; - name = malloc( strlen(lemp->filename) + strlen(suffix) + 5 ); + name = malloc( lemonStrlen(lemp->filename) + lemonStrlen(suffix) + 5 ); if( name==0 ){ fprintf(stderr,"Can't allocate space for a filename.\n"); exit(1); @@ -2748,7 +2791,7 @@ struct lemon *lemp; maxlen = 10; for(i=0; i<lemp->nsymbol; i++){ sp = lemp->symbols[i]; - len = (int)strlen(sp->name); + len = lemonStrlen(sp->name); if( len>maxlen ) maxlen = len; } ncolumns = 76/(maxlen+5); @@ -2956,7 +2999,7 @@ int modemask; char c; #ifdef __WIN32__ - for (cp = argv0 + strlen(argv0); cp-- > argv0; ) + for (cp = argv0 + lemonStrlen(argv0); cp-- > argv0; ) { if( *cp == '\\' || *cp == '/' ) break; @@ -2967,18 +3010,18 @@ int modemask; if( cp ){ c = *cp; *cp = 0; - path = (char *)malloc( strlen(argv0) + strlen(name) + 2 ); + path = (char *)malloc( lemonStrlen(argv0) + lemonStrlen(name) + 2 ); if( path ) sprintf(path,"%s/%s",argv0,name); *cp = c; }else{ extern char *getenv(); pathlist = getenv("PATH"); if( pathlist==0 ) pathlist = ".:/bin:/usr/bin"; - path = (char *)malloc( strlen(pathlist)+strlen(name)+2 ); + path = (char *)malloc( lemonStrlen(pathlist)+lemonStrlen(name)+2 ); if( path!=0 ){ while( *pathlist ){ cp = strchr(pathlist,':'); - if( cp==0 ) cp = &pathlist[strlen(pathlist)]; + if( cp==0 ) cp = &pathlist[lemonStrlen(pathlist)]; c = *cp; *cp = 0; sprintf(path,"%s/%s",pathlist,name); @@ -3103,16 +3146,13 @@ char *filename; } /* Print a string to the file and keep the linenumber up to date */ -PRIVATE void tplt_print(out,lemp,str,strln,lineno) +PRIVATE void tplt_print(out,lemp,str,lineno) FILE *out; struct lemon *lemp; char *str; -int strln; int *lineno; { if( str==0 ) return; - tplt_linedir(out,strln,lemp->filename); - (*lineno)++; while( *str ){ if( *str=='\n' ) (*lineno)++; putc(*str,out); @@ -3122,8 +3162,10 @@ int *lineno; putc('\n',out); (*lineno)++; } - tplt_linedir(out,*lineno+1,lemp->outname); - (*lineno)+=1; + if (!lemp->nolinenosflag) { + (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); + } + return; } @@ -3139,21 +3181,18 @@ int *lineno; { char *cp = 0; - int linecnt = 0; if( sp->type==TERMINAL ){ cp = lemp->tokendest; if( cp==0 ) return; - tplt_linedir(out,lemp->tokendestln,lemp->filename); - fprintf(out,"{"); + fprintf(out,"{\n"); (*lineno)++; }else if( sp->destructor ){ cp = sp->destructor; - tplt_linedir(out,sp->destructorln,lemp->filename); - fprintf(out,"{"); + fprintf(out,"{\n"); (*lineno)++; + if (!lemp->nolinenosflag) { (*lineno)++; tplt_linedir(out,sp->destLineno,lemp->filename); } }else if( lemp->vardest ){ cp = lemp->vardest; if( cp==0 ) return; - tplt_linedir(out,lemp->vardestln,lemp->filename); - fprintf(out,"{"); + fprintf(out,"{\n"); (*lineno)++; }else{ assert( 0 ); /* Cannot happen */ } @@ -3163,12 +3202,14 @@ int *lineno; cp++; continue; } - if( *cp=='\n' ) linecnt++; + if( *cp=='\n' ) (*lineno)++; fputc(*cp,out); } - (*lineno) += 3 + linecnt; - fprintf(out,"}\n"); - tplt_linedir(out,*lineno,lemp->outname); + fprintf(out,"\n"); (*lineno)++; + if (!lemp->nolinenosflag) { + (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); + } + fprintf(out,"}\n"); (*lineno)++; return; } @@ -3216,7 +3257,7 @@ PRIVATE char *append_str(char *zText, int n, int p1, int p2, int bNoSubst){ used += n; assert( used>=0 ); } - n = (int)strlen(zText); + n = lemonStrlen(zText); } if( n+sizeof(zInt)*2+used >= (size_t)alloced ){ alloced = n + sizeof(zInt)*2 + used + 200; @@ -3229,7 +3270,7 @@ PRIVATE char *append_str(char *zText, int n, int p1, int p2, int bNoSubst){ sprintf(zInt, "%d", p1); p1 = p2; strcpy(&z[used], zInt); - used += (int)strlen(&z[used]); + used += lemonStrlen(&z[used]); zText++; n--; }else{ @@ -3316,7 +3357,7 @@ PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){ lemp->errorcnt++; }else if( rp->rhsalias[i]==0 ){ if( has_destructor(rp->rhs[i],lemp) ){ - append_str(" yy_destructor(%d,&yymsp[%d].minor);\n", 0, + append_str(" yy_destructor(yypParser,%d,&yymsp[%d].minor);\n", 0, rp->rhs[i]->index,i-rp->nrhs+1,0); }else{ /* No destructor defined for this term */ @@ -3340,18 +3381,16 @@ struct lemon *lemp; int *lineno; { char *cp; - int linecnt = 0; /* Generate code to do the reduce action */ if( rp->code ){ - tplt_linedir(out,rp->line,lemp->filename); + if (!lemp->nolinenosflag) { (*lineno)++; tplt_linedir(out,rp->line,lemp->filename); } fprintf(out,"{%s",rp->code); for(cp=rp->code; *cp; cp++){ - if( *cp=='\n' ) linecnt++; + if( *cp=='\n' ) (*lineno)++; } /* End loop */ - (*lineno) += 3 + linecnt; - fprintf(out,"}\n"); - tplt_linedir(out,*lineno,lemp->outname); + fprintf(out,"}\n"); (*lineno)++; + if (!lemp->nolinenosflag) { (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); } } /* End if( rp->code ) */ return; @@ -3384,13 +3423,13 @@ int mhflag; /* True if generating makeheaders output */ types = (char**)calloc( arraysize, sizeof(char*) ); maxdtlength = 0; if( lemp->vartype ){ - maxdtlength = (int)strlen(lemp->vartype); + maxdtlength = lemonStrlen(lemp->vartype); } for(i=0; i<lemp->nsymbol; i++){ int len; struct symbol *sp = lemp->symbols[i]; if( sp->datatype==0 ) continue; - len = (int)strlen(sp->datatype); + len = lemonStrlen(sp->datatype); if( len>maxdtlength ) maxdtlength = len; } stddt = (char*)malloc( maxdtlength*2 + 1 ); @@ -3423,6 +3462,10 @@ int mhflag; /* True if generating makeheaders output */ while( *cp ) stddt[j++] = *cp++; while( j>0 && isspace(stddt[j-1]) ) j--; stddt[j] = 0; + if( lemp->tokentype && strcmp(stddt, lemp->tokentype)==0 ){ + sp->dtnum = 0; + continue; + } hash = 0; for(j=0; stddt[j]; j++){ hash = hash*53 + stddt[j]; @@ -3438,7 +3481,7 @@ int mhflag; /* True if generating makeheaders output */ } if( types[hash]==0 ){ sp->dtnum = hash + 1; - types[hash] = (char*)malloc( strlen(stddt)+1 ); + types[hash] = (char*)malloc( lemonStrlen(stddt)+1 ); if( types[hash]==0 ){ fprintf(stderr,"Out of memory.\n"); exit(1); @@ -3455,6 +3498,7 @@ int mhflag; /* True if generating makeheaders output */ lemp->tokentype?lemp->tokentype:"void*"); lineno++; if( mhflag ){ fprintf(out,"#endif\n"); lineno++; } fprintf(out,"typedef union {\n"); lineno++; + fprintf(out," int yyinit;\n"); lineno++; fprintf(out," %sTOKENTYPE yy0;\n",name); lineno++; for(i=0; i<arraysize; i++){ if( types[i]==0 ) continue; @@ -3561,7 +3605,7 @@ int mhflag; /* Output in makeheaders format if true */ tplt_xfer(lemp->name,in,out,&lineno); /* Generate the include code, if any */ - tplt_print(out,lemp,lemp->include,lemp->includeln,&lineno); + tplt_print(out,lemp,lemp->include,&lineno); if( mhflag ){ char *name = file_makename(lemp, ".h"); fprintf(out,"#include \"%s\"\n", name); lineno++; @@ -3585,7 +3629,7 @@ int mhflag; /* Output in makeheaders format if true */ /* Generate the defines */ fprintf(out,"#define YYCODETYPE %s\n", - minimum_size_type(0, lemp->nsymbol+5)); lineno++; + minimum_size_type(0, lemp->nsymbol+1)); lineno++; fprintf(out,"#define YYNOCODE %d\n",lemp->nsymbol+1); lineno++; fprintf(out,"#define YYACTIONTYPE %s\n", minimum_size_type(0, lemp->nstate+lemp->nrule+5)); lineno++; @@ -3607,7 +3651,7 @@ int mhflag; /* Output in makeheaders format if true */ name = lemp->name ? lemp->name : "Parse"; if( lemp->arg && lemp->arg[0] ){ size_t i; - i = strlen(lemp->arg); + i = lemonStrlen(lemp->arg); while( i>=1 && isspace(lemp->arg[i-1]) ) i--; while( i>=1 && (isalnum(lemp->arg[i-1]) || lemp->arg[i-1]=='_') ) i--; fprintf(out,"#define %sARG_SDECL %s;\n",name,lemp->arg); lineno++; @@ -3800,7 +3844,9 @@ int mhflag; /* Output in makeheaders format if true */ /* Generate the table of fallback tokens. */ if( lemp->has_fallback ){ - for(i=0; i<lemp->nterminal; i++){ + int mx = lemp->nterminal - 1; + while( mx>0 && lemp->symbols[mx]->fallback==0 ){ mx--; } + for(i=0; i<=mx; i++){ struct symbol *p = lemp->symbols[i]; if( p->fallback==0 ){ fprintf(out, " 0, /* %10s => nothing */\n", p->name); @@ -3824,7 +3870,7 @@ int mhflag; /* Output in makeheaders format if true */ tplt_xfer(lemp->name,in,out,&lineno); /* Generate a table containing a text string that describes every - ** rule in the rule set of the grammer. This information is used + ** rule in the rule set of the grammar. This information is used ** when tracing REDUCE actions. */ for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){ @@ -3840,11 +3886,15 @@ int mhflag; /* Output in makeheaders format if true */ ** (In other words, generate the %destructor actions) */ if( lemp->tokendest ){ + int once = 1; for(i=0; i<lemp->nsymbol; i++){ struct symbol *sp = lemp->symbols[i]; if( sp==0 || sp->type!=TERMINAL ) continue; - fprintf(out," case %d: /* %s */\n", - sp->index, sp->name); lineno++; + if( once ){ + fprintf(out, " /* TERMINAL Destructor */\n"); lineno++; + once = 0; + } + fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; } for(i=0; i<lemp->nsymbol && lemp->symbols[i]->type!=TERMINAL; i++); if( i<lemp->nsymbol ){ @@ -3854,24 +3904,27 @@ int mhflag; /* Output in makeheaders format if true */ } if( lemp->vardest ){ struct symbol *dflt_sp = 0; + int once = 1; for(i=0; i<lemp->nsymbol; i++){ struct symbol *sp = lemp->symbols[i]; if( sp==0 || sp->type==TERMINAL || sp->index<=0 || sp->destructor!=0 ) continue; - fprintf(out," case %d: /* %s */\n", - sp->index, sp->name); lineno++; + if( once ){ + fprintf(out, " /* Default NON-TERMINAL Destructor */\n"); lineno++; + once = 0; + } + fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; dflt_sp = sp; } if( dflt_sp!=0 ){ emit_destructor_code(out,dflt_sp,lemp,&lineno); - fprintf(out," break;\n"); lineno++; } + fprintf(out," break;\n"); lineno++; } for(i=0; i<lemp->nsymbol; i++){ struct symbol *sp = lemp->symbols[i]; if( sp==0 || sp->type==TERMINAL || sp->destructor==0 ) continue; - fprintf(out," case %d: /* %s */\n", - sp->index, sp->name); lineno++; + fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; /* Combine duplicate destructors into a single case */ for(j=i+1; j<lemp->nsymbol; j++){ @@ -3891,7 +3944,7 @@ int mhflag; /* Output in makeheaders format if true */ tplt_xfer(lemp->name,in,out,&lineno); /* Generate code which executes whenever the parser stack overflows */ - tplt_print(out,lemp,lemp->overflow,lemp->overflowln,&lineno); + tplt_print(out,lemp,lemp->overflow,&lineno); tplt_xfer(lemp->name,in,out,&lineno); /* Generate the table of rule information @@ -3908,39 +3961,53 @@ int mhflag; /* Output in makeheaders format if true */ for(rp=lemp->rule; rp; rp=rp->next){ translate_code(lemp, rp); } + /* First output rules other than the default: rule */ for(rp=lemp->rule; rp; rp=rp->next){ - struct rule *rp2; + struct rule *rp2; /* Other rules with the same action */ if( rp->code==0 ) continue; + if( rp->code[0]=='\n' && rp->code[1]==0 ) continue; /* Will be default: */ fprintf(out," case %d: /* ",rp->index); writeRuleText(out, rp); - fprintf(out, " */\n"); lineno++; + fprintf(out," */\n"); lineno++; for(rp2=rp->next; rp2; rp2=rp2->next){ if( rp2->code==rp->code ){ fprintf(out," case %d: /*",rp2->index); writeRuleText(out, rp2); - fprintf(out," */\n"); lineno++; + fprintf(out, " */ yytestcase(yyruleno==%d);\n", rp2->index); lineno++; rp2->code = 0; } } emit_code(out,rp,lemp,&lineno); fprintf(out," break;\n"); lineno++; + rp->code = 0; } + /* Finally, output the default: rule. We choose as the default: all + ** empty actions. */ + fprintf(out," default:\n"); lineno++; + for(rp=lemp->rule; rp; rp=rp->next){ + if( rp->code==0 ) continue; + assert( rp->code[0]=='\n' && rp->code[1]==0 ); + fprintf(out," /* (%d) ", rp->index); + writeRuleText(out, rp); + fprintf(out," */ yytestcase(yyruleno==%d);\n", rp->index); lineno++; + } + fprintf(out," break;\n"); lineno++; tplt_xfer(lemp->name,in,out,&lineno); /* Generate code which executes if a parse fails */ - tplt_print(out,lemp,lemp->failure,lemp->failureln,&lineno); + tplt_print(out,lemp,lemp->failure,&lineno); tplt_xfer(lemp->name,in,out,&lineno); /* Generate code which executes when a syntax error occurs */ - tplt_print(out,lemp,lemp->error,lemp->errorln,&lineno); + tplt_print(out,lemp,lemp->error,&lineno); tplt_xfer(lemp->name,in,out,&lineno); /* Generate code which executes when the parser accepts its input */ - tplt_print(out,lemp,lemp->accept,lemp->acceptln,&lineno); + tplt_print(out,lemp,lemp->accept,&lineno); tplt_xfer(lemp->name,in,out,&lineno); /* Append any addition code the user desires */ - tplt_print(out,lemp,lemp->extracode,lemp->extracodeln,&lineno); + tplt_print(out,lemp,lemp->extracode,&lineno); fclose(in); fclose(out); @@ -4028,7 +4095,7 @@ struct lemon *lemp; /* Do not make a default if the number of rules to default ** is not at least 1 or if the wildcard token is a possbile - ** lookahed. + ** lookahead. */ if( nbest<1 || usesWildcard ) continue; @@ -4196,7 +4263,7 @@ char *y; if( y==0 ) return 0; z = Strsafe_find(y); - if( z==0 && (z=malloc( strlen(y)+1 ))!=0 ){ + if( z==0 && (z=malloc( lemonStrlen(y)+1 ))!=0 ){ strcpy(z,y); Strsafe_insert(z); } @@ -4343,6 +4410,7 @@ char *x; sp->firstset = 0; sp->lambda = LEMON_FALSE; sp->destructor = 0; + sp->destLineno = 0; sp->datatype = 0; sp->useCnt = 0; Symbol_insert(sp,sp->name); diff --git a/tools/lemon/lempar.c b/tools/lemon/lempar.c index c6c032ca9..6e9bf92c2 100644 --- a/tools/lemon/lempar.c +++ b/tools/lemon/lempar.c @@ -1,8 +1,8 @@ /* Driver template for the LEMON parser generator. ** The author disclaims copyright to this source code. */ -/* First off, code is included which follows the "include" declaration -** in the input file. */ +/* First off, code is included that follows the "include" declaration +** in the input grammar file. */ #include <stdio.h> #include <string.h> #include <assert.h> @@ -69,7 +69,24 @@ #define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1) #define YY_ERROR_ACTION (YYNSTATE+YYNRULE) -/* Next are that tables used to determine what action to take based on the +/* The yyzerominor constant is used to initialize instances of +** YYMINORTYPE objects to zero. */ +static const YYMINORTYPE yyzerominor = { 0 }; + +/* Define the yytestcase() macro to be a no-op if is not already defined +** otherwise. +** +** Applications can choose to define yytestcase() in the %include section +** to a macro that can assist in verifying code coverage. For production +** code the yytestcase() macro should be turned off. But it is useful +** for testing. +*/ +#ifndef yytestcase +# define yytestcase(X) +#endif + + +/* Next are the tables used to determine what action to take based on the ** current state and lookahead token. These tables are used to implement ** functions that take a state number and lookahead value and return an ** action integer. @@ -124,7 +141,7 @@ ** ** %fallback ID X Y Z. ** -** appears in the grammer, then ID becomes a fallback token for X, Y, +** appears in the grammar, then ID becomes a fallback token for X, Y, ** and Z. Whenever one of the tokens X, Y, or Z is input to the parser ** but it does not parse, the type of the token is changed to ID and ** the parse is retried before an error is thrown. @@ -148,11 +165,11 @@ static const YYCODETYPE yyFallback[] = { ** It is sometimes called the "minor" token. */ struct yyStackEntry { - int stateno; /* The state-number */ - int major; /* The major token value. This is the code - ** number for the token at this stack level */ - YYMINORTYPE minor; /* The user-supplied minor token value. This - ** is the value of the token */ + YYACTIONTYPE stateno; /* The state-number */ + YYCODETYPE major; /* The major token value. This is the code + ** number for the token at this stack level */ + YYMINORTYPE minor; /* The user-supplied minor token value. This + ** is the value of the token */ }; typedef struct yyStackEntry yyStackEntry; @@ -160,6 +177,9 @@ typedef struct yyStackEntry yyStackEntry; ** the following structure */ struct yyParser { int yyidx; /* Index of top element in stack */ +#ifdef YYTRACKMAXSTACKDEPTH + int yyidxMax; /* Maximum value of yyidx */ +#endif int yyerrcnt; /* Shifts left before out of the error */ ParseARG_SDECL /* A place to hold %extra_argument */ #if YYSTACKDEPTH<=0 @@ -259,7 +279,12 @@ void *ParseAlloc(void *(CDECL *mallocProc)(size_t)){ pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) ); if( pParser ){ pParser->yyidx = -1; +#ifdef YYTRACKMAXSTACKDEPTH + pParser->yyidxMax = 0; +#endif #if YYSTACKDEPTH<=0 + pParser->yystack = NULL; + pParser->yystksz = 0; yyGrowStack(pParser); #endif } @@ -271,7 +296,12 @@ void *ParseAlloc(void *(CDECL *mallocProc)(size_t)){ ** "yymajor" is the symbol code, and "yypminor" is a pointer to ** the value. */ -static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){ +static void yy_destructor( + yyParser *yypParser, /* The parser */ + YYCODETYPE yymajor, /* Type code for object to destroy */ + YYMINORTYPE *yypminor /* The object to be destroyed */ +){ + ParseARG_FETCH; switch( yymajor ){ /* Here is inserted the actions which take place when a ** terminal or non-terminal is destroyed. This can happen @@ -309,7 +339,7 @@ static int yy_pop_parser_stack(yyParser *pParser){ } #endif yymajor = yytos->major; - yy_destructor( yymajor, &yytos->minor); + yy_destructor(pParser, yymajor, &yytos->minor); pParser->yyidx--; return yymajor; } @@ -339,6 +369,16 @@ void ParseFree( (*freeProc)((void*)pParser); } +/* +** Return the peak depth of the stack for a parser. +*/ +#ifdef YYTRACKMAXSTACKDEPTH +int ParseStackPeak(void *p){ + yyParser *pParser = (yyParser*)p; + return pParser->yyidxMax; +} +#endif + /* ** Find the appropriate action for a parser given the terminal ** look-ahead token iLookAhead. @@ -362,7 +402,7 @@ static int yy_find_shift_action( if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){ if( iLookAhead>0 ){ #ifdef YYFALLBACK - int iFallback; /* Fallback token */ + YYCODETYPE iFallback; /* Fallback token */ if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0]) && (iFallback = yyFallback[iLookAhead])!=0 ){ #ifndef NDEBUG @@ -408,18 +448,25 @@ static int yy_find_reduce_action( YYCODETYPE iLookAhead /* The look-ahead token */ ){ int i; - if( stateno>YY_REDUCE_MAX || - (i = yy_reduce_ofst[stateno])==YY_REDUCE_USE_DFLT ){ +#ifdef YYERRORSYMBOL + if( stateno>YY_REDUCE_MAX ){ return yy_default[stateno]; } +#else + assert( stateno<=YY_REDUCE_MAX ); +#endif + i = yy_reduce_ofst[stateno]; assert( i!=YY_REDUCE_USE_DFLT ); assert( iLookAhead!=YYNOCODE ); i += iLookAhead; +#ifdef YYERRORSYMBOL if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){ return yy_default[stateno]; - }else{ - return yy_action[i]; } +#else + assert( i>=0 && i<YY_SZ_ACTTAB ); + assert( yy_lookahead[i]==iLookAhead ); +#endif return yy_action[i]; } @@ -436,7 +483,7 @@ static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){ #endif while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will execute if the parser - ** stack every overflows */ + ** stack ever overflows */ %% ParseARG_STORE; /* Suppress warning about unused %extra_argument var */ } @@ -448,10 +495,15 @@ static void yy_shift( yyParser *yypParser, /* The parser to be shifted */ int yyNewState, /* The new state to shift in */ int yyMajor, /* The major token to shift in */ - YYMINORTYPE *yypMinor /* Pointer ot the minor token to shift in */ + YYMINORTYPE *yypMinor /* Pointer to the minor token to shift in */ ){ yyStackEntry *yytos; yypParser->yyidx++; +#ifdef YYTRACKMAXSTACKDEPTH + if( yypParser->yyidx>yypParser->yyidxMax ){ + yypParser->yyidxMax = yypParser->yyidx; + } +#endif #if YYSTACKDEPTH>0 if( yypParser->yyidx>=YYSTACKDEPTH ){ yyStackOverflow(yypParser, yypMinor); @@ -467,8 +519,8 @@ static void yy_shift( } #endif yytos = &yypParser->yystack[yypParser->yyidx]; - yytos->stateno = yyNewState; - yytos->major = yyMajor; + yytos->stateno = (YYACTIONTYPE)yyNewState; + yytos->major = (YYCODETYPE)yyMajor; yytos->minor = *yypMinor; #ifndef NDEBUG if( yyTraceFILE && yypParser->yyidx>0 ){ @@ -531,8 +583,8 @@ static void yy_reduce( ** from wireshark this week. Clearly they are stressing Lemon in ways ** that it has not been previously stressed... (SQLite ticket #2172) */ - memset(&yygotominor, 0, sizeof(yygotominor)); - + /*memset(&yygotominor, 0, sizeof(yygotominor));*/ + yygotominor = yyzerominor; switch( yyruleno ){ /* Beginning here are the reduction cases. A typical example @@ -548,7 +600,7 @@ static void yy_reduce( yygoto = yyRuleInfo[yyruleno].lhs; yysize = yyRuleInfo[yyruleno].nrhs; yypParser->yyidx -= yysize; - yyact = yy_find_reduce_action(yymsp[-yysize].stateno,yygoto); + yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); if( yyact < YYNSTATE ){ #ifdef NDEBUG /* If we are not debugging and the reduce action popped at least @@ -558,8 +610,8 @@ static void yy_reduce( if( yysize ){ yypParser->yyidx++; yymsp -= yysize-1; - yymsp->stateno = yyact; - yymsp->major = yygoto; + yymsp->stateno = (YYACTIONTYPE)yyact; + yymsp->major = (YYCODETYPE)yygoto; yymsp->minor = yygotominor; }else #endif @@ -575,6 +627,7 @@ static void yy_reduce( /* ** The following code executes when the parse fails */ +#ifndef YYNOERRORRECOVERY static void yy_parse_failed( yyParser *yypParser /* The parser */ ){ @@ -590,6 +643,7 @@ static void yy_parse_failed( %% ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ } +#endif /* YYNOERRORRECOVERY */ /* ** The following code executes when a syntax error first occurs. @@ -662,7 +716,8 @@ void Parse( if( yypParser->yyidx<0 ){ #if YYSTACKDEPTH<=0 if( yypParser->yystksz <=0 ){ - memset(&yyminorunion, 0, sizeof(yyminorunion)); + /*memset(&yyminorunion, 0, sizeof(yyminorunion));*/ + yyminorunion = yyzerominor; yyStackOverflow(yypParser, &yyminorunion); return; } @@ -683,7 +738,7 @@ void Parse( #endif do{ - yyact = yy_find_shift_action(yypParser,yymajor); + yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); if( yyact<YYNSTATE ){ assert( !yyendofinput ); /* Impossible to shift the $ token */ yy_shift(yypParser,yyact,yymajor,&yyminorunion); @@ -732,7 +787,7 @@ void Parse( yyTracePrompt,yyTokenName[yymajor]); } #endif - yy_destructor(yymajor,&yyminorunion); + yy_destructor(yypParser, (YYCODETYPE)yymajor,&yyminorunion); yymajor = YYNOCODE; }else{ while( @@ -745,7 +800,7 @@ void Parse( yy_pop_parser_stack(yypParser); } if( yypParser->yyidx < 0 || yymajor==0 ){ - yy_destructor(yymajor,&yyminorunion); + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); yy_parse_failed(yypParser); yymajor = YYNOCODE; }else if( yymx!=YYERRORSYMBOL ){ @@ -756,6 +811,18 @@ void Parse( } yypParser->yyerrcnt = 3; yyerrorhit = 1; +#elif defined(YYNOERRORRECOVERY) + /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to + ** do any kind of error recovery. Instead, simply invoke the syntax + ** error routine and continue going as if nothing had happened. + ** + ** Applications can set this macro (for example inside %include) if + ** they intend to abandon the parse upon the first syntax error seen. + */ + yy_syntax_error(yypParser,yymajor,yyminorunion); + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); + yymajor = YYNOCODE; + #else /* YYERRORSYMBOL is not defined */ /* This is what we do if the grammar does not define ERROR: ** @@ -770,7 +837,7 @@ void Parse( yy_syntax_error(yypParser,yymajor,yyminorunion); } yypParser->yyerrcnt = 3; - yy_destructor(yymajor,&yyminorunion); + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); if( yyendofinput ){ yy_parse_failed(yypParser); } From e489867c18de28361976a3305530e568b89a23fa Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 13 Mar 2010 03:28:34 +0000 Subject: [PATCH 022/232] - Changed some tokens and split the token definitions into a separate file so that their symbol names and their string names can be maintained in the same place. SVN r2207 (scripting) --- src/sc_man.cpp | 114 +------------------------------------- src/sc_man.h | 116 +-------------------------------------- src/sc_man_scanner.re | 13 +++++ src/sc_man_tokens.h | 125 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 144 insertions(+), 224 deletions(-) create mode 100644 src/sc_man_tokens.h diff --git a/src/sc_man.cpp b/src/sc_man.cpp index b69aa1ce0..298676dc6 100644 --- a/src/sc_man.cpp +++ b/src/sc_man.cpp @@ -812,116 +812,8 @@ FString FScanner::TokenName (int token, const char *string) { static const char *const names[] = { - "identifier", - "string constant", - "name constant", - "integer constant", - "float constant", - "'...'", - "'>>='", - "'<<='", - "'+='", - "'-='", - "'*='", - "'/='", - "'%='", - "'&='", - "'^='", - "'|='", - "'>>'", - "'>>>'", - "'<<'", - "'++'", - "'--'", - "'&&'", - "'||'", - "'<='", - "'>='", - "'=='", - "'!='", - "'action'", - "'break'", - "'case'", - "'const'", - "'continue'", - "'default'", - "'do'", - "'else'", - "'for'", - "'if'", - "'return'", - "'states'", - "'switch'", - "'until'", - "'while'", - "'bool'", - "'float'", - "'double'", - "'char'", - "'byte'", - "'sbyte'", - "'short'", - "'ushort'", - "'int'", - "'uint'", - "'long'", - "'ulong'", - "'void'", - "'struct'", - "'class'", - "'mode'", - "'enum'", - "'name'", - "'string'", - "'sound'", - "'state'", - "'color'", - "'goto'", - "'abstract'", - "'foreach'", - "'true'", - "'false'", - "'none'", - "'new'", - "'instanceof'", - "'auto'", - "'exec'", - "'defaultproperties'", - "'native'", - "'out'", - "'ref'", - "'event'", - "'static'", - "'transient'", - "'volatile'", - "'final'", - "'throws'", - "'extends'", - "'public'", - "'protected'", - "'private'", - "'dot'", - "'cross'", - "'ignores'", - "'localized'", - "'latent'", - "'singular'", - "'config'", - "'coerce'", - "'iterator'", - "'optional'", - "'export'", - "'virtual'", - "'super'", - "'global'", - "'self'", - "'stop'", - "'#include'", - "'fixed_t'", - "'angle_t'", - "'abs'", - "'random'", - "'random2'" +#define xx(sym,str) str, +#include "sc_man_tokens.h" }; FString work; @@ -992,7 +884,7 @@ void STACK_ARGS FScanner::ScriptError (const char *message, ...) //========================================================================== // -// FScanner::ScriptError +// FScanner::ScriptMessage // //========================================================================== diff --git a/src/sc_man.h b/src/sc_man.h index 1e5dc289d..777e8cdcd 100644 --- a/src/sc_man.h +++ b/src/sc_man.h @@ -99,119 +99,9 @@ protected: enum { - TK_Identifier = 257, - TK_StringConst, - TK_NameConst, - TK_IntConst, - TK_FloatConst, - TK_Ellipsis, // ... - TK_RShiftEq, // >>= - TK_URShiftEq, // >>>= - TK_LShiftEq, // <<= - TK_AddEq, // += - TK_SubEq, // -= - TK_MulEq, // *= - TK_DivEq, // /= - TK_ModEq, // %= - TK_AndEq, // &= - TK_XorEq, // ^= - TK_OrEq, // |= - TK_RShift, // >> - TK_URShift, // >>> - TK_LShift, // << - TK_Incr, // ++ - TK_Decr, // -- - TK_AndAnd, // && - TK_OrOr, // || - TK_Leq, // <= - TK_Geq, // >= - TK_Eq, // == - TK_Neq, // != - TK_Action, - TK_Break, - TK_Case, - TK_Const, - TK_Continue, - TK_Default, - TK_Do, - TK_Else, - TK_For, - TK_If, - TK_Return, - TK_Switch, - TK_Until, - TK_While, - TK_Bool, - TK_Float, - TK_Double, - TK_Char, - TK_Byte, - TK_SByte, - TK_Short, - TK_UShort, - TK_Int, - TK_UInt, - TK_Long, - TK_ULong, - TK_Void, - TK_Struct, - TK_Class, - TK_Mode, - TK_Enum, - TK_Name, - TK_String, - TK_Sound, - TK_State, - TK_Color, - TK_Goto, - TK_Abstract, - TK_ForEach, - TK_True, - TK_False, - TK_None, - TK_New, - TK_InstanceOf, - TK_Auto, - TK_Exec, - TK_DefaultProperties, - TK_Native, - TK_Var, - TK_Out, - TK_Ref, - TK_Event, - TK_Static, - TK_Transient, - TK_Volatile, - TK_Final, - TK_Throws, - TK_Extends, - TK_Public, - TK_Protected, - TK_Private, - TK_Dot, - TK_Cross, - TK_Ignores, - TK_Localized, - TK_Latent, - TK_Singular, - TK_Config, - TK_Coerce, - TK_Iterator, - TK_Optional, - TK_Export, - TK_Virtual, - TK_Super, - TK_Global, - TK_Self, - TK_Stop, - TK_Include, - TK_Fixed_t, - TK_Angle_t, - TK_Abs, - TK_Random, - TK_Random2, - TK_FRandom, - + TK_SequenceStart = 256, +#define xx(sym,str) sym, +#include "sc_man_tokens.h" TK_LastToken }; diff --git a/src/sc_man_scanner.re b/src/sc_man_scanner.re index ff0945db3..66058ac8c 100644 --- a/src/sc_man_scanner.re +++ b/src/sc_man_scanner.re @@ -96,6 +96,12 @@ std2: 'sound' { RET(TK_Sound); } 'state' { RET(TK_State); } 'color' { RET(TK_Color); } + 'vector' { RET(TK_Vector); } + 'map' { RET(TK_Map); } + 'array' { RET(TK_Array); } + 'in' { RET(TK_In); } + 'sizeof' { RET(TK_SizeOf); } + 'alignof' { RET(TK_AlignOf); } /* Other keywords from UnrealScript */ 'abstract' { RET(TK_Abstract); } @@ -138,6 +144,9 @@ std2: 'self' { RET(TK_Self); } 'stop' { RET(TK_Stop); } + 'is' { RET(TK_Is); } + 'replaces' { RET(TK_Replaces); } + /* Needed for decorate action functions */ 'action' { RET(TK_Action); } @@ -164,6 +173,7 @@ std2: (['] (any\[\n'])* [']) { RET(TK_NameConst); } + ".." { RET(TK_DotDot); } "..." { RET(TK_Ellipsis); } ">>>=" { RET(TK_URShiftEq); } ">>=" { RET(TK_RShiftEq); } @@ -187,6 +197,9 @@ std2: ">=" { RET(TK_Geq); } "==" { RET(TK_Eq); } "!=" { RET(TK_Neq); } + "~==" { RET(TK_ApproxEq); } + "<>=" { RET(TK_LtGtEq); } + "**" { RET(TK_MulMul); } ";" { RET(';'); } "{" { RET('{'); } "}" { RET('}'); } diff --git a/src/sc_man_tokens.h b/src/sc_man_tokens.h new file mode 100644 index 000000000..9dde74972 --- /dev/null +++ b/src/sc_man_tokens.h @@ -0,0 +1,125 @@ +xx(TK_Identifier, "identifier") +xx(TK_StringConst, "string constant") +xx(TK_NameConst, "name constant") +xx(TK_IntConst, "integer constant") +xx(TK_FloatConst, "float constant") +xx(TK_DotDot, "'..'") +xx(TK_Ellipsis, "'...'") +xx(TK_RShiftEq, "'>>='") +xx(TK_URShiftEq, "'>>>='") +xx(TK_LShiftEq, "'<<='") +xx(TK_AddEq, "'+='") +xx(TK_SubEq, "'-='") +xx(TK_MulEq, "'*='") +xx(TK_DivEq, "'/='") +xx(TK_ModEq, "'%='") +xx(TK_AndEq, "'&='") +xx(TK_XorEq, "'^='") +xx(TK_OrEq, "'|='") +xx(TK_RShift, "'>>'") +xx(TK_URShift, "'>>>'") +xx(TK_LShift, "'<<'") +xx(TK_Incr, "'++'") +xx(TK_Decr, "'--'") +xx(TK_AndAnd, "'&&'") +xx(TK_OrOr, "'||'") +xx(TK_Leq, "'<='") +xx(TK_Geq, "'>='") +xx(TK_Eq, "'=='") +xx(TK_Neq, "'!='") +xx(TK_ApproxEq, "'~=='") +xx(TK_LtGtEq, "'<>='") +xx(TK_MulMul, "'**'") +xx(TK_Action, "'action'") +xx(TK_Break, "'break'") +xx(TK_Case, "'case'") +xx(TK_Const, "'const'") +xx(TK_Continue, "'continue'") +xx(TK_Default, "'default'") +xx(TK_Do, "'do'") +xx(TK_Else, "'else'") +xx(TK_For, "'for'") +xx(TK_If, "'if'") +xx(TK_Return, "'return'") +xx(TK_Switch, "'switch'") +xx(TK_Until, "'until'") +xx(TK_While, "'while'") +xx(TK_Bool, "'bool'") +xx(TK_Float, "'float'") +xx(TK_Double, "'double'") +xx(TK_Char, "'char'") +xx(TK_Byte, "'byte'") +xx(TK_SByte, "'sbyte'") +xx(TK_Short, "'short'") +xx(TK_UShort, "'ushort'") +xx(TK_Int, "'int'") +xx(TK_UInt, "'uint'") +xx(TK_Long, "'long'") +xx(TK_ULong, "'ulong'") +xx(TK_Void, "'void'") +xx(TK_Struct, "'struct'") +xx(TK_Class, "'class'") +xx(TK_Mode, "'mode'") +xx(TK_Enum, "'enum'") +xx(TK_Name, "'name'") +xx(TK_String, "'string'") +xx(TK_Sound, "'sound'") +xx(TK_State, "'state'") +xx(TK_Color, "'color'") +xx(TK_Goto, "'goto'") +xx(TK_Abstract, "'abstract'") +xx(TK_ForEach, "'foreach'") +xx(TK_True, "'true'") +xx(TK_False, "'false'") +xx(TK_None, "'none'") +xx(TK_New, "'new'") +xx(TK_InstanceOf, "'instanceof'") +xx(TK_Auto, "'auto'") +xx(TK_Exec, "'exec'") +xx(TK_DefaultProperties, "'defaultproperties'") +xx(TK_Native, "'native'") +xx(TK_Var, "'var'") +xx(TK_Out, "'out'") +xx(TK_Ref, "'ref'") +xx(TK_Event, "'event'") +xx(TK_Static, "'static'") +xx(TK_Transient, "'transient'") +xx(TK_Volatile, "'volatile'") +xx(TK_Final, "'final'") +xx(TK_Throws, "'throws'") +xx(TK_Extends, "'extends'") +xx(TK_Public, "'public'") +xx(TK_Protected, "'protected'") +xx(TK_Private, "'private'") +xx(TK_Dot, "'dot'") +xx(TK_Cross, "'cross'") +xx(TK_Ignores, "'ignores'") +xx(TK_Localized, "'localized'") +xx(TK_Latent, "'latent'") +xx(TK_Singular, "'singular'") +xx(TK_Config, "'config'") +xx(TK_Coerce, "'coerce'") +xx(TK_Iterator, "'iterator'") +xx(TK_Optional, "'optional'") +xx(TK_Export, "'expert'") +xx(TK_Virtual, "'virtual'") +xx(TK_Super, "'super'") +xx(TK_Global, "'global'") +xx(TK_Self, "'self'") +xx(TK_Stop, "'stop'") +xx(TK_Include, "'include'") +xx(TK_Fixed_t, "'fixed_t'") +xx(TK_Angle_t, "'angle_t'") +xx(TK_Abs, "'abs'") +xx(TK_Random, "'random'") +xx(TK_Random2, "'random2'") +xx(TK_FRandom, "'frandom'") +xx(TK_Is, "'is'") +xx(TK_Replaces, "'replaces'") +xx(TK_Vector, "'vector'") +xx(TK_Map, "'map'") +xx(TK_Array, "'array'") +xx(TK_In, "'in'") +xx(TK_SizeOf, "'sizeof'") +xx(TK_AlignOf, "'alignof'") +#undef xx From 7aa402b2a5f1471b533b974c0e0c916ad613cb6c Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 19 Mar 2010 04:04:13 +0000 Subject: [PATCH 023/232] - Add a preliminary grammar and a test driver for it. SVN r2233 (scripting) --- src/CMakeLists.txt | 7 + src/c_dispatch.h | 1 + src/sc_man.cpp | 30 +++ src/sc_man.h | 2 + src/sc_man_scanner.re | 50 +++- src/sc_man_tokens.h | 8 + src/thingdef/thingdef_parse.cpp | 20 +- src/zscript/vm.h | 4 +- src/zscript/zcc-parse.lemon | 443 ++++++++++++++++++++++++++++++++ src/zscript/zcc_parser.cpp | 331 ++++++++++++++++++++++++ zdoom.vcproj | 92 +++++++ 11 files changed, 972 insertions(+), 16 deletions(-) create mode 100644 src/zscript/zcc-parse.lemon create mode 100644 src/zscript/zcc_parser.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 67e83a96e..c360dfcb7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -495,6 +495,12 @@ add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c ${CMAKE_CUR WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} DEPENDS lemon ${CMAKE_CURRENT_SOURCE_DIR}/xlat/xlat_parser.y ) +add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.c ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.h + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/zscript/zcc-parse.lemon . + COMMAND ${CMAKE_BINARY_DIR}/tools/lemon/lemon zcc-parse.lemon + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS lemon ${CMAKE_CURRENT_SOURCE_DIR}/zscript/zcc-parse.lemon ) + add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h COMMAND ${CMAKE_BINARY_DIR}/tools/re2c/re2c --no-generation-date -s -o ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h ${CMAKE_CURRENT_SOURCE_DIR}/sc_man_scanner.re DEPENDS re2c ${CMAKE_CURRENT_SOURCE_DIR}/sc_man_scanner.re ) @@ -773,6 +779,7 @@ add_executable( zdoom WIN32 zscript/vmdisasm.cpp zscript/vmexec.cpp zscript/vmframe.cpp + zscript/zcc_parser.cpp autozend.cpp ) set_source_files_properties( xlat/parse_xlat.cpp PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c" ) diff --git a/src/c_dispatch.h b/src/c_dispatch.h index cde53996a..96e375ea2 100644 --- a/src/c_dispatch.h +++ b/src/c_dispatch.h @@ -159,5 +159,6 @@ void ResetButtonStates (); // Same as above, but also clear bDown extern unsigned int MakeKey (const char *s); extern unsigned int MakeKey (const char *s, size_t len); +extern unsigned int SuperFastHash (const char *data, size_t len); #endif //__C_DISPATCH_H__ diff --git a/src/sc_man.cpp b/src/sc_man.cpp index 298676dc6..505c9c0d4 100644 --- a/src/sc_man.cpp +++ b/src/sc_man.cpp @@ -119,6 +119,7 @@ FScanner &FScanner::operator=(const FScanner &other) LastGotLine = other.LastGotLine; CMode = other.CMode; Escape = other.Escape; + StateMode = other.StateMode; // Copy public members if (other.String == other.StringBuffer) @@ -262,6 +263,7 @@ void FScanner::PrepareScript () LastGotLine = 1; CMode = false; Escape = true; + StateMode = 0; StringBuffer[0] = '\0'; BigStringBuffer = ""; } @@ -359,6 +361,34 @@ void FScanner::SetEscape (bool esc) Escape = esc; } +//========================================================================== +// +// FScanner :: SetStateMode +// +// Enters state mode. This mode is very permissive for identifiers, which +// it returns as TOK_NonWhitespace. The only character sequences that are +// not returned as such are these: +// +// * stop +// * wait +// * fail +// * loop +// * goto - Automatically exits state mode after it's seen. +// * : +// * ; +// * } - Automatically exits state mode after it's seen. +// +// Quoted strings are returned as TOK_NonWhitespace, minus the quotes. In +// addition, any two consecutive sequences of TOK_NonWhitespace also exit +// state mode. +// +//========================================================================== + +void FScanner::SetStateMode(bool stately) +{ + StateMode = stately ? 2 : 0; +} + //========================================================================== // // FScanner::ScanString diff --git a/src/sc_man.h b/src/sc_man.h index 777e8cdcd..cc2c1c537 100644 --- a/src/sc_man.h +++ b/src/sc_man.h @@ -26,6 +26,7 @@ public: void SetCMode(bool cmode); void SetEscape(bool esc); + void SetStateMode(bool stately); const SavedPos SavePos(); void RestorePos(const SavedPos &pos); @@ -94,6 +95,7 @@ protected: const char *LastGotPtr; int LastGotLine; bool CMode; + BYTE StateMode; bool Escape; }; diff --git a/src/sc_man_scanner.re b/src/sc_man_scanner.re index 66058ac8c..d8070b53a 100644 --- a/src/sc_man_scanner.re +++ b/src/sc_man_scanner.re @@ -49,9 +49,34 @@ std2: TOK2 = (NWS\STOP1); TOKC2 = (NWS\STOPC); */ - if (tokens) // A well-defined scanner, based on the c.re example. - { #define RET(x) TokenType = x; goto normal_token; + if (tokens && StateMode != 0) + { + /*!re2c + "/*" { goto comment; } /* C comment */ + "//" (any\"\n")* "\n" { goto newline; } /* C++ comment */ + + (["](([\\]["])|[^"])*["]) { RET(TK_StringConst); } + 'stop' { RET(TK_Stop); } + 'wait' { RET(TK_Wait); } + 'fail' { RET(TK_Fail); } + 'loop' { RET(TK_Loop); } + 'goto' { StateMode = 0; RET(TK_Goto); } + ":" { RET(':'); } + ";" { RET(';'); } + "}" { StateMode = 0; RET('}'); } + + WSP+ { goto std1; } + "\n" { goto newline; } + + TOKS = (NWS\[/":;}]); + TOKS* ([/] (TOKS\[*]) TOKS*)* + { RET(TK_NonWhitespace); } + + */ + } + else if (tokens) // A well-defined scanner, based on the c.re example. + { /*!re2c "/*" { goto comment; } /* C comment */ "//" (any\"\n")* "\n" { goto newline; } /* C++ comment */ @@ -146,8 +171,9 @@ std2: 'is' { RET(TK_Is); } 'replaces' { RET(TK_Replaces); } - - /* Needed for decorate action functions */ + 'states' { RET(TK_States); } + 'meta' { RET(TK_Meta); } + 'deprecated' { RET(TK_Deprecated); } 'action' { RET(TK_Action); } /* other DECORATE top level keywords */ @@ -200,6 +226,7 @@ std2: "~==" { RET(TK_ApproxEq); } "<>=" { RET(TK_LtGtEq); } "**" { RET(TK_MulMul); } + "::" { RET(TK_ColonColon); } ";" { RET(';'); } "{" { RET('{'); } "}" { RET('}'); } @@ -352,6 +379,10 @@ normal_token: { memcpy (StringBuffer, tok+1, StringLen); } + if (StateMode && TokenType == TK_StringConst) + { + TokenType = TK_NonWhitespace; + } } else { @@ -364,6 +395,17 @@ normal_token: memcpy (StringBuffer, tok, StringLen); } } + if (tokens && StateMode) + { // State mode is exited after two consecutive TK_NonWhitespace tokens + if (TokenType == TK_NonWhitespace) + { + StateMode--; + } + else + { + StateMode = 2; + } + } if (StringLen < MAX_STRING_SIZE) { String = StringBuffer; diff --git a/src/sc_man_tokens.h b/src/sc_man_tokens.h index 9dde74972..de0815447 100644 --- a/src/sc_man_tokens.h +++ b/src/sc_man_tokens.h @@ -3,6 +3,8 @@ xx(TK_StringConst, "string constant") xx(TK_NameConst, "name constant") xx(TK_IntConst, "integer constant") xx(TK_FloatConst, "float constant") +xx(TK_NonWhitespace, "non-whitespace") +xx(TK_ColonColon, "'::'") xx(TK_DotDot, "'..'") xx(TK_Ellipsis, "'...'") xx(TK_RShiftEq, "'>>='") @@ -122,4 +124,10 @@ xx(TK_Array, "'array'") xx(TK_In, "'in'") xx(TK_SizeOf, "'sizeof'") xx(TK_AlignOf, "'alignof'") +xx(TK_States, "'states'") +xx(TK_Loop, "'loop'") +xx(TK_Fail, "'fail'") +xx(TK_Wait, "'wait'") +xx(TK_Meta, "'meta'") +xx(TK_Deprecated, "'deprecated'") #undef xx diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index ed3ed4b15..9a9d99cc2 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -859,16 +859,6 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag) FScriptPosition::ErrorCounter++; } } - else if (!propname.CompareNoCase("States")) - { - if (bag.StateSet) - { - sc.ScriptMessage("'%s' contains multiple state declarations", bag.Info->Class->TypeName.GetChars()); - FScriptPosition::ErrorCounter++; - } - ParseStates(sc, bag.Info, (AActor *)bag.Info->Class->Defaults, bag); - bag.StateSet=true; - } else if (MatchString(propname, statenames) != -1) { bag.statedef.SetStateLabel(propname, CheckState (sc, bag.Info->Class)); @@ -1184,6 +1174,16 @@ static void ParseActor(FScanner &sc) ParseActorProperty(sc, bag); break; + case TK_States: + if (bag.StateSet) + { + sc.ScriptMessage("'%s' contains multiple state declarations", bag.Info->Class->TypeName.GetChars()); + FScriptPosition::ErrorCounter++; + } + ParseStates(sc, bag.Info, (AActor *)bag.Info->Class->Defaults, bag); + bag.StateSet = true; + break; + case '+': case '-': ParseActorFlag(sc, bag, sc.TokenType); diff --git a/src/zscript/vm.h b/src/zscript/vm.h index 72e2141d5..c7d3e302f 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -867,7 +867,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction #define PARAM_SOUND_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FSoundID x = param[p].i; #define PARAM_COLOR_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); PalEntry x; x.d = param[p].i; #define PARAM_FLOAT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); double x = param[p].f; -#define PARAM_FIXED_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); fixed_t x = fixed_t(param[p].f * 65536.0); +#define PARAM_FIXED_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); fixed_t x = FLOAT2FIXED(param[p].f); #define PARAM_ANGLE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); angle_t x = angle_t(param[p].f * (ANGLE_90 / 90.0)); #define PARAM_STRING_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_STRING); FString x = param[p].s(); #define PARAM_STATE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].a == NULL)); FState *x = (FState *)param[p].a; @@ -885,7 +885,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction #define PARAM_SOUND_OPT_AT(p,x) FSoundID x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x = FSoundID(param[p].i); } else #define PARAM_COLOR_OPT_AT(p,x) PalEntry x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x.d = param[p].i; } else #define PARAM_FLOAT_OPT_AT(p,x) double x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_FLOAT); x = param[p].f; } else -#define PARAM_FIXED_OPT_AT(p,x) fixed_t x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_FLOAT); x = fixed_t(param[p].f * 65536.0); } else +#define PARAM_FIXED_OPT_AT(p,x) fixed_t x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_FLOAT); x = FLOAT2FIXED(param[p].f); } else #define PARAM_ANGLE_OPT_AT(p,x) angle_t x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_FLOAT); x = angle_t(param[p].f * (ANGLE_90 / 90.0)); } else #define PARAM_STRING_OPT_AT(p,x) FString x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_STRING); x = param[p].s(); } else #define PARAM_STATE_OPT_AT(p,x) FState *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].a == NULL)); x = (FState *)param[p].a; } else diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon new file mode 100644 index 000000000..d699f37da --- /dev/null +++ b/src/zscript/zcc-parse.lemon @@ -0,0 +1,443 @@ +%token_prefix ZCC_ +%token_type { ZCCToken } +%token_destructor {} // just to avoid a compiler warning +%name ZCCParse +%extra_argument { FScanner *sc } +%syntax_error +{ + FString unexpected, expecting; + + int i; + int stateno = yypParser->yystack[yypParser->yyidx].stateno; + + unexpected << "Unexpected " << ZCCTokenName(yymajor); + + // Determine all the terminals that the parser would have accepted at this point + // (see yy_find_shift_action). This list can get quite long. Is it worthwhile to + // print it when not debugging the grammar, or would that be too confusing to + // the average user? + if (stateno < YY_SHIFT_MAX && (i = yy_shift_ofst[stateno])!=YY_SHIFT_USE_DFLT) + { + for (int j = 1; j < YYERRORSYMBOL; ++j) + { + int k = i + j; + if (k >= 0 && k < YY_SZ_ACTTAB && yy_lookahead[k] == j) + { + expecting << (expecting.IsEmpty() ? "Expecting " : " or ") << ZCCTokenName(j); + } + } + } + sc->ScriptMessage("%s\n%s\n", unexpected.GetChars(), expecting.GetChars()); +} +%parse_accept { sc->ScriptMessage("input accepted\n"); } +%parse_failure { /**failed = true;*/ } + +%nonassoc EQ MULEQ DIVEQ MODEQ ADDEQ SUBEQ LSHEQ RSHEQ ANDEQ OREQ XOREQ. +%right QUESTION COLON. +%left OROR. +%left ANDAND. +%left EQEQ NEQ APPROXEQ. +%left LT GT LTEQ GTEQ LTGTEQ IS. +%left DOTDOT. +%left OR. /* Note that this is like the Ruby precedence for these */ +%left XOR. /* three operators and not the C precedence, since */ +%left AND. /* they are higher priority than the comparisons. */ +%left LSH RSH. +%left SUB ADD. +%left MUL DIV MOD CROSSPROD DOTPROD. +%left POW. +%right UNARY ADDADD SUBSUB. +%left DOT LPAREN LBRACKET. +%left SCOPE. + + +main ::= translation_unit. { sc->ScriptMessage("Parse complete\n"); } + +translation_unit ::= . +translation_unit ::= translation_unit external_declaration. +translation_unit ::= translation_unit EOF. +translation_unit ::= error. + +external_declaration ::= class_definition. + +/* Optional bits. */ +opt_semicolon ::= . +opt_semicolon ::= SEMICOLON. + +opt_comma ::= . +opt_comma ::= COMMA. + +opt_expr ::= . +opt_expr ::= expr. + + +/* A class definition. Can only occur at global scope. */ +class_definition ::= CLASS id_or_string class_ancestry class_flags class_body. + +id_or_string ::= IDENTIFIER. +id_or_string ::= string_constant. + +class_ancestry ::= . +class_ancestry ::= COLON id_or_string. + +class_flags ::= . +class_flags ::= class_flags ABSTRACT. +class_flags ::= class_flags NATIVE. +class_flags ::= class_flags REPLACES id_or_string. + + +class_body ::= SEMICOLON class_innards EOF. +class_body ::= LBRACE class_innards RBRACE. + +class_innards ::= . +class_innards ::= class_innards class_member. + +/* Classes can define variables, functions, enums, structs, states, constants, and defaults. */ +class_member ::= declarator. +class_member ::= enum_def. +class_member ::= struct_def. +class_member ::= states_def. +class_member ::= default_def. +class_member ::= const_def. + +/* Structs can define variables, enums, and structs. */ +struct_def ::= STRUCT IDENTIFIER LBRACE struct_body RBRACE opt_semicolon. +struct_member ::= declarator_no_fun. +struct_member ::= enum_def. + +/* Enumerators are lists of named integers. */ +enum_def ::= ENUM IDENTIFIER enum_type LBRACE enum_list opt_comma RBRACE opt_semicolon. + +enum_type ::= . +enum_type ::= COLON int_type. + +enum_list ::= enumerator. +enum_list ::= enum_list COMMA enumerator. + +enumerator ::= IDENTIFIER. +enumerator ::= IDENTIFIER EQ expr. /* Expression must be constant. */ + +/* States */ +states_def ::= STATES scanner_mode LBRACE states_body RBRACE. + +/* We use a special scanner mode to allow for sprite names and frame characters + * to not be quoted even if they contain special characters. The scanner_mode + * nonterminal is used to enter this mode. The scanner automatically leaves it + * upon pre-defined conditions. See the comments by FScanner::SetStateMode(). + * + * Note that rules are reduced *after* one token of lookahead has been + * consumed, so this nonterminal must be placed one token before we want it to + * take effect. For example, in states_def above, the scanner mode will be + * set immediately after LBRACE is consumed, rather than immediately after + * STATES is consumed. + */ +scanner_mode ::= . { sc->SetStateMode(true); } + +states_body ::= . +states_body ::= error. +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_flow ::= state_flow_type scanner_mode SEMICOLON. +state_flow_type ::= STOP. +state_flow_type ::= WAIT. +state_flow_type ::= FAIL. +state_flow_type ::= LOOP. +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_opts ::= . +state_opts ::= state_opts BRIGHT. +state_opts ::= state_opts OFFSET LPAREN expr COMMA expr RPAREN. +state_opts ::= state_opts LIGHT LPAREN light_list RPAREN. + +light_list ::= STRCONST. +light_list ::= light_list COMMA STRCONST. + +/* A state action can be either a compound statement or a single action function call. */ +state_action ::= LBRACE statement_list scanner_mode RBRACE. +state_action ::= LBRACE error scanner_mode RBRACE. +state_action ::= state_call scanner_mode SEMICOLON. + +state_call ::= . +state_call ::= IDENTIFIER state_call_parms. +state_call_parms ::= . +state_call_parms ::= LPAREN opt_expr_list RPAREN. +state_call_parms ::= LPAREN error RPAREN. + +dotted_identifier ::= IDENTIFIER. +dotted_identifier ::= dotted_identifier DOT IDENTIFIER. + +/* Definition of a default class instance. */ +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_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) */ + +vector_size ::= . +vector_size ::= LT INTCONST GT. + +/* Type names can also be used as identifiers in contexts where type names + * are not normally allowed. */ +%fallback IDENTIFIER + 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<type> */ +aggregate_type ::= CLASS class_restrictor. /* class<type> */ +class_restrictor ::= . +class_restrictor ::= LT IDENTIFIER GT. + +type ::= type_name. +type ::= aggregate_type. + +type_list ::= type array_size. /* A comma-separated list of types */ +type_list ::= type_list COMMA type array_size. + +type_list_or_void ::= VOID. +type_list_or_void ::= type_list. + +array_size ::= . +array_size ::= array_size LBRACKET opt_expr RBRACKET. + +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. + +variables_or_function ::= IDENTIFIER LPAREN func_params RPAREN func_const opt_func_body. /* Function */ +variables_or_function ::= variable_list SEMICOLON. +variables_or_function ::= error SEMICOLON. + +variable_list ::= IDENTIFIER array_size. +variable_list ::= variable_list COMMA IDENTIFIER array_size. + +decl_flags ::= . +decl_flags ::= decl_flags NATIVE. +decl_flags ::= decl_flags STATIC. +decl_flags ::= decl_flags PRIVATE. +decl_flags ::= decl_flags PROTECTED. +decl_flags ::= decl_flags LATENT. +decl_flags ::= decl_flags FINAL. +decl_flags ::= decl_flags META. +decl_flags ::= decl_flags ACTION. +decl_flags ::= decl_flags DEPRECATED LPAREN string_constant RPAREN. + +func_const ::= . +func_const ::= CONST. + +opt_func_body ::= SEMICOLON. +opt_func_body ::= function_body. + +func_params ::= . /* empty */ +func_params ::= VOID. +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_flags ::= . +func_param_flags ::= func_param_flags IN. +func_param_flags ::= func_param_flags OUT. +func_param_flags ::= func_param_flags OPTIONAL. + +struct_body ::= struct_member. +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 */ + +/* 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. + +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] + +/* 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 */ + +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 ::= expr EQEQ expr. /* a == b */ +expr ::= expr NEQ expr. /* a != b */ +expr ::= expr APPROXEQ expr. /* a ~== b */ + +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 ::= expr SCOPE expr. + +expr ::= expr QUESTION expr COLON expr. + +opt_expr_list ::= . +opt_expr_list ::= expr_list. + +expr_list ::= expr. +expr_list ::= expr_list COMMA expr. + +/* 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. + +named_expr_list ::= named_expr. +named_expr_list ::= named_expr_list COMMA named_expr. + +named_expr ::= IDENTIFIER COLON expr. + +/* Allow C-like concatenation of adjacent string constants. */ +string_constant ::= STRCONST. +string_constant ::= string_constant STRCONST. + +constant ::= string_constant. +constant ::= INTCONST. +constant ::= FLOATCONST. + +function_body ::= compound_statement. + +statement ::= labeled_statement. +statement ::= compound_statement. +statement ::= expression_statement. +statement ::= selection_statement. +statement ::= iteration_statement. +statement ::= jump_statement. +statement ::= assign_statement. +statement ::= local_var. +statement ::= error SEMICOLON. + +jump_statement ::= CONTINUE SEMICOLON. +jump_statement ::= BREAK SEMICOLON. +jump_statement ::= RETURN SEMICOLON. +jump_statement ::= RETURN expr_list SEMICOLON. + +compound_statement ::= LBRACE RBRACE. +compound_statement ::= LBRACE statement_list RBRACE. +compound_statement ::= LBRACE error RBRACE. + +statement_list ::= statement. +statement_list ::= statement_list statement. + +expression_statement ::= SEMICOLON. +expression_statement ::= expr SEMICOLON. + +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. + +while_or_until ::= WHILE. +while_or_until ::= UNTIL. + +for_init_expr ::= . +for_init_expr ::= expr. +for_init_expr ::= type variable_list EQ expr_list. +for_init_expr ::= assign_expr. + +for_bump_expr ::= . +for_bump_expr ::= expr. +for_bump_expr ::= assign_expr. + +/* Resolve the shift-reduce conflict here in favor of the shift. + * This is the default behavior, but using precedence symbols + * lets us do it without warnings. + */ +%left IF. +%left ELSE. +selection_statement ::= if_front. [IF] +selection_statement ::= if_front ELSE statement. [ELSE] + +selection_statement ::= SWITCH LPAREN expr RPAREN statement. + +if_front ::= IF LPAREN expr RPAREN statement. + +labeled_statement ::= CASE expr COLON. +labeled_statement ::= DEFAULT COLON. + +assign_statement ::= assign_expr SEMICOLON. [EQ] + +assign_expr ::= expr_list assign_op expr_list. +assign_op ::= EQ. +assign_op ::= MULEQ. +assign_op ::= DIVEQ. +assign_op ::= MODEQ. +assign_op ::= ADDEQ. +assign_op ::= SUBEQ. +assign_op ::= LSHEQ. +assign_op ::= RSHEQ. +assign_op ::= ANDEQ. +assign_op ::= OREQ. +assign_op ::= XOREQ. + +local_var ::= type variable_list var_init SEMICOLON. + +var_init ::= . +var_init ::= EQ expr_list. diff --git a/src/zscript/zcc_parser.cpp b/src/zscript/zcc_parser.cpp new file mode 100644 index 000000000..8e3abe942 --- /dev/null +++ b/src/zscript/zcc_parser.cpp @@ -0,0 +1,331 @@ +#include "dobject.h" +#include "sc_man.h" +#include "c_console.h" +#include "c_dispatch.h" +#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]; +}; + +static FString ZCCTokenName(int terminal); + +#include "zcc-parse.h" +#include "zcc-parse.c" + +static TMap<SWORD, SWORD> TokenMap; +static SWORD BackTokenMap[YYERRORSYMBOL]; // YYERRORSYMBOL immediately follows the terminals described by the grammar + +static void InitTokenMap() +{ +#define TOKENDEF(sc, zcc) TokenMap.Insert(sc, zcc); BackTokenMap[zcc] = sc + TOKENDEF('=', ZCC_EQ); + TOKENDEF(TK_MulEq, ZCC_MULEQ); + TOKENDEF(TK_DivEq, ZCC_DIVEQ); + TOKENDEF(TK_ModEq, ZCC_MODEQ); + TOKENDEF(TK_AddEq, ZCC_ADDEQ); + TOKENDEF(TK_SubEq, ZCC_SUBEQ); + TOKENDEF(TK_LShiftEq, ZCC_LSHEQ); + TOKENDEF(TK_RShiftEq, ZCC_RSHEQ); + TOKENDEF(TK_AndEq, ZCC_ANDEQ); + TOKENDEF(TK_OrEq, ZCC_OREQ); + TOKENDEF(TK_XorEq, ZCC_XOREQ); + TOKENDEF('?', ZCC_QUESTION); + TOKENDEF(':', ZCC_COLON); + TOKENDEF(TK_OrOr, ZCC_OROR); + TOKENDEF(TK_AndAnd, ZCC_ANDAND); + TOKENDEF(TK_Eq, ZCC_EQEQ); + TOKENDEF(TK_Neq, ZCC_NEQ); + TOKENDEF(TK_ApproxEq, ZCC_APPROXEQ); + TOKENDEF('<', ZCC_LT); + TOKENDEF('>', ZCC_GT); + TOKENDEF(TK_Leq, ZCC_LTEQ); + TOKENDEF(TK_Geq, ZCC_GTEQ); + TOKENDEF(TK_LtGtEq, ZCC_LTGTEQ); + TOKENDEF(TK_Is, ZCC_IS); + TOKENDEF(TK_DotDot, ZCC_DOTDOT); + TOKENDEF('|', ZCC_OR); + TOKENDEF('^', ZCC_XOR); + TOKENDEF('&', ZCC_AND); + TOKENDEF(TK_LShift, ZCC_LSH); + TOKENDEF(TK_RShift, ZCC_RSH); + TOKENDEF('-', ZCC_SUB); + TOKENDEF('+', ZCC_ADD); + TOKENDEF('*', ZCC_MUL); + TOKENDEF('/', ZCC_DIV); + TOKENDEF('%', ZCC_MOD); + TOKENDEF(TK_Cross, ZCC_CROSSPROD); + TOKENDEF(TK_Dot, ZCC_DOTPROD); + TOKENDEF(TK_MulMul, ZCC_POW); + TOKENDEF(TK_Incr, ZCC_ADDADD); + TOKENDEF(TK_Decr, ZCC_SUBSUB); + TOKENDEF('.', ZCC_DOT); + TOKENDEF('(', ZCC_LPAREN); + TOKENDEF(')', ZCC_RPAREN); + TOKENDEF(TK_ColonColon, ZCC_SCOPE); + TOKENDEF(';', ZCC_SEMICOLON); + TOKENDEF(',', ZCC_COMMA); + TOKENDEF(TK_Class, ZCC_CLASS); + TOKENDEF(TK_Abstract, ZCC_ABSTRACT); + TOKENDEF(TK_Native, ZCC_NATIVE); + TOKENDEF(TK_Replaces, ZCC_REPLACES); + TOKENDEF(TK_Static, ZCC_STATIC); + TOKENDEF(TK_Private, ZCC_PRIVATE); + TOKENDEF(TK_Protected, ZCC_PROTECTED); + TOKENDEF(TK_Latent, ZCC_LATENT); + TOKENDEF(TK_Final, ZCC_FINAL); + TOKENDEF(TK_Meta, ZCC_META); + TOKENDEF(TK_Deprecated, ZCC_DEPRECATED); + TOKENDEF('{', ZCC_LBRACE); + TOKENDEF('}', ZCC_RBRACE); + TOKENDEF(TK_Struct, ZCC_STRUCT); + TOKENDEF(TK_Enum, ZCC_ENUM); + TOKENDEF(TK_SByte, ZCC_SBYTE); + TOKENDEF(TK_Byte, ZCC_BYTE); + TOKENDEF(TK_Short, ZCC_SHORT); + TOKENDEF(TK_UShort, ZCC_USHORT); + TOKENDEF(TK_Int, ZCC_INT); + TOKENDEF(TK_UInt, ZCC_UINT); + TOKENDEF(TK_Bool, ZCC_BOOL); + TOKENDEF(TK_Float, ZCC_FLOAT); + TOKENDEF(TK_Double, ZCC_DOUBLE); + TOKENDEF(TK_String, ZCC_STRING); + TOKENDEF(TK_Vector, ZCC_VECTOR); + TOKENDEF(TK_Name, ZCC_NAME); + TOKENDEF(TK_Map, ZCC_MAP); + TOKENDEF(TK_Array, ZCC_ARRAY); + TOKENDEF(TK_Void, ZCC_VOID); + TOKENDEF('[', ZCC_LBRACKET); + TOKENDEF(']', ZCC_RBRACKET); + TOKENDEF(TK_In, ZCC_IN); + TOKENDEF(TK_Out, ZCC_OUT); + TOKENDEF(TK_Optional, ZCC_OPTIONAL); + TOKENDEF(TK_Super, ZCC_SUPER); + TOKENDEF(TK_Self, ZCC_SELF); + TOKENDEF('~', ZCC_TILDE); + TOKENDEF('!', ZCC_BANG); + TOKENDEF(TK_SizeOf, ZCC_SIZEOF); + TOKENDEF(TK_AlignOf, ZCC_ALIGNOF); + TOKENDEF(TK_Continue, ZCC_CONTINUE); + TOKENDEF(TK_Break, ZCC_BREAK); + TOKENDEF(TK_Return, ZCC_RETURN); + TOKENDEF(TK_Do, ZCC_DO); + TOKENDEF(TK_For, ZCC_FOR); + TOKENDEF(TK_While, ZCC_WHILE); + TOKENDEF(TK_Until, ZCC_UNTIL); + TOKENDEF(TK_If, ZCC_IF); + TOKENDEF(TK_Else, ZCC_ELSE); + TOKENDEF(TK_Switch, ZCC_SWITCH); + TOKENDEF(TK_Case, ZCC_CASE); + TOKENDEF(TK_Default, ZCC_DEFAULT); + TOKENDEF(TK_Const, ZCC_CONST); + TOKENDEF(TK_Stop, ZCC_STOP); + TOKENDEF(TK_Wait, ZCC_WAIT); + TOKENDEF(TK_Fail, ZCC_FAIL); + TOKENDEF(TK_Loop, ZCC_LOOP); + TOKENDEF(TK_Goto, ZCC_GOTO); + TOKENDEF(TK_States, ZCC_STATES); + + TOKENDEF(TK_Identifier, ZCC_IDENTIFIER); + TOKENDEF(TK_StringConst, ZCC_STRCONST); + TOKENDEF(TK_IntConst, ZCC_INTCONST); + TOKENDEF(TK_FloatConst, ZCC_FLOATCONST); + TOKENDEF(TK_NonWhitespace, ZCC_NWS); +#undef TOKENDEF +} + +static void DoParse(const char *filename) +{ + if (TokenMap.CountUsed() == 0) + { + InitTokenMap(); + } + + FScanner sc; + StringTable strings; + void *parser; + int tokentype; + int lump; + bool failed; + ZCCToken value; + + lump = Wads.CheckNumForFullName(filename, true); + if (lump >= 0) + { + sc.OpenLumpNum(lump); + } + else if (FileExists(filename)) + { + sc.OpenFile(filename); + } + else + { + Printf("Could not find script lump '%s'\n", filename); + return; + } + + parser = ZCCParseAlloc(malloc); + failed = false; + FILE *f = fopen("trace.txt", "w"); + ZCCParseTrace(f, ""); + while (sc.GetToken()) + { + if (sc.TokenType == TK_StringConst) + { + value.String = strings.Get(sc.String, sc.StringLen); + tokentype = ZCC_STRCONST; + } + else if (sc.TokenType == TK_IntConst) + { + value.Int = sc.Number; + tokentype = ZCC_INTCONST; + } + else if (sc.TokenType == TK_FloatConst) + { + value.Float = sc.Float; + tokentype = ZCC_FLOATCONST; + } + else if (sc.TokenType == TK_Identifier) + { + value.Int = FName(sc.String); + tokentype = ZCC_IDENTIFIER; + } + else if (sc.TokenType == TK_NonWhitespace) + { + value.Int = FName(sc.String); + tokentype = ZCC_NWS; + } + else + { + SWORD *zcctoken = TokenMap.CheckKey(sc.TokenType); + if (zcctoken != NULL) + { + tokentype = *zcctoken; + } + else + { + sc.ScriptMessage("Unexpected token %s.\n", sc.TokenName(sc.TokenType).GetChars()); + break; + } + } + ZCCParse(parser, tokentype, value, &sc); + if (failed) + { + sc.ScriptMessage("Parse failed\n"); + break; + } + } + value.Int = -1; + ZCCParse(parser, ZCC_EOF, value, &sc); + ZCCParse(parser, 0, value, &sc); + ZCCParseFree(parser, free); + if (f != NULL) + { + fclose(f); + } +} + +CCMD(parse) +{ + if (argv.argc() == 2) + { + DoParse(argv[1]); + } +} + +static FString ZCCTokenName(int terminal) +{ + if (terminal == ZCC_EOF) + { + return "end of file"; + } + int sc_token; + if (terminal > 0 && terminal < countof(BackTokenMap)) + { + sc_token = BackTokenMap[terminal]; + if (sc_token == 0) + { // This token was not initialized. Whoops! + sc_token = -terminal; + } + } + else + { // This should never happen. + sc_token = -terminal; + } + return FScanner::TokenName(sc_token); +} diff --git a/zdoom.vcproj b/zdoom.vcproj index c37dd5d91..689a1fe3d 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -1501,6 +1501,10 @@ RelativePath=".\src\sc_man.h" > </File> + <File + RelativePath=".\src\sc_man_tokens.h" + > + </File> <File RelativePath=".\src\skins.h" > @@ -6461,6 +6465,94 @@ RelativePath=".\src\zscript\vmops.h" > </File> + <File + RelativePath=".\src\zscript\zcc-parse.c" + > + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|x64" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> + <FileConfiguration + Name="Debug|x64" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> + </File> + <File + RelativePath=".\src\zscript\zcc-parse.h" + > + </File> + <File + RelativePath=".\src\zscript\zcc-parse.lemon" + > + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCustomBuildTool" + Description="Generating zcc-parse.c and zcc-parse.h..." + CommandLine="tools\lemon\lemon.exe "$(InputPath)"
" + Outputs="$(InputDir)\zcc-parse.c;$(InputDir)\zcc-parse.h" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|x64" + > + <Tool + Name="VCCustomBuildTool" + Description="Generating zcc-parse.c and zcc-parse.h..." + CommandLine="tools\lemon\lemon.exe "$(InputPath)"
" + Outputs="$(InputDir)\zcc-parse.c;$(InputDir)\zcc-parse.h" + /> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCustomBuildTool" + Description="Generating zcc-parse.c and zcc-parse.h..." + CommandLine="tools\lemon\lemon.exe "$(InputPath)"
" + Outputs="$(InputDir)\zcc-parse.c;$(InputDir)\zcc-parse.h" + /> + </FileConfiguration> + <FileConfiguration + Name="Debug|x64" + > + <Tool + Name="VCCustomBuildTool" + Description="Generating zcc-parse.c and zcc-parse.h..." + CommandLine="tools\lemon\lemon.exe "$(InputPath)"
" + Outputs="$(InputDir)\zcc-parse.c;$(InputDir)\zcc-parse.h" + /> + </FileConfiguration> + </File> + <File + RelativePath=".\src\zscript\zcc_parser.cpp" + > + </File> </Filter> </Files> <Globals> From f88f6012301fe99075400029dd3a7522abd46f55 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 24 Mar 2010 02:49:37 +0000 Subject: [PATCH 024/232] - Removed the third parameter from dumpclasses when it was restricted it to Actors, because I have no idea what that was all about. - Got rid of FActorInfo and merged it into a new PClassActor. SVN r2240 (scripting) --- src/actor.h | 19 ++- src/b_bot.cpp | 2 +- src/b_think.cpp | 2 +- src/d_dehacked.cpp | 88 ++++++------ src/d_main.cpp | 4 +- src/d_net.cpp | 8 +- src/decallib.cpp | 2 +- src/dobject.cpp | 18 +-- src/dobject.h | 53 ++++++- src/dobjtype.cpp | 147 ++++---------------- src/dobjtype.h | 11 +- src/f_finale.cpp | 12 +- src/farchive.h | 6 + src/g_doom/a_archvile.cpp | 2 +- src/g_doom/a_bossbrain.cpp | 9 +- src/g_doom/a_doomweaps.cpp | 31 +++-- src/g_doom/a_fatso.cpp | 16 ++- src/g_doom/a_scriptedmarine.cpp | 22 +-- src/g_game.cpp | 11 +- src/g_heretic/a_hereticmisc.cpp | 4 +- src/g_heretic/a_hereticweaps.cpp | 11 +- src/g_hexen/a_blastradius.cpp | 2 +- src/g_hexen/a_clericmace.cpp | 6 +- src/g_hexen/a_clericstaff.cpp | 4 +- src/g_hexen/a_fighteraxe.cpp | 6 +- src/g_hexen/a_fighterhammer.cpp | 8 +- src/g_hexen/a_fighterplayer.cpp | 8 +- src/g_hexen/a_magelightning.cpp | 4 +- src/g_hexen/hexen_sbar.cpp | 14 +- src/g_mapinfo.cpp | 4 +- src/g_raven/a_artitele.cpp | 2 +- src/g_raven/a_minotaur.cpp | 2 +- src/g_shared/a_armor.cpp | 2 +- src/g_shared/a_artifacts.cpp | 6 +- src/g_shared/a_artifacts.h | 2 +- src/g_shared/a_bridge.cpp | 5 +- src/g_shared/a_keys.cpp | 22 +-- src/g_shared/a_morph.cpp | 4 +- src/g_shared/a_pickups.cpp | 14 +- src/g_shared/a_pickups.h | 40 +++--- src/g_shared/a_randomspawner.cpp | 8 +- src/g_shared/a_weaponpiece.h | 2 +- src/g_shared/a_weapons.cpp | 95 ++++++------- src/g_shared/sbarinfo_commands.cpp | 52 +++---- src/g_shared/shared_hud.cpp | 41 +++--- src/g_strife/a_strifeglobal.h | 2 +- src/g_strife/a_strifeitems.cpp | 2 +- src/g_strife/a_thingstoblowup.cpp | 2 - src/g_strife/strife_sbar.cpp | 2 +- src/info.cpp | 198 +++++++++++++++++++++------ src/info.h | 47 ++++--- src/m_cheat.cpp | 78 +++++------ src/p_acs.cpp | 41 +++--- src/p_conversation.cpp | 18 +-- src/p_conversation.h | 10 +- src/p_enemy.cpp | 8 +- src/p_interaction.cpp | 9 +- src/p_lnspec.cpp | 24 ++-- src/p_local.h | 6 +- src/p_map.cpp | 17 ++- src/p_mobj.cpp | 45 +++--- src/p_pspr.cpp | 2 +- src/p_pspr.h | 10 +- src/p_states.cpp | 190 +++++++++++++------------ src/p_things.cpp | 16 +-- src/p_user.cpp | 9 +- src/thingdef/olddecorations.cpp | 111 +++++++-------- src/thingdef/thingdef.cpp | 110 +++++++-------- src/thingdef/thingdef.h | 62 ++++----- src/thingdef/thingdef_codeptr.cpp | 20 +-- src/thingdef/thingdef_data.cpp | 8 +- src/thingdef/thingdef_exp.cpp | 58 ++++---- src/thingdef/thingdef_exp.h | 10 +- src/thingdef/thingdef_expression.cpp | 28 ++-- src/thingdef/thingdef_parse.cpp | 68 ++++----- src/thingdef/thingdef_properties.cpp | 150 ++++++++++---------- src/thingdef/thingdef_states.cpp | 12 +- src/zscript/vm.h | 4 +- 78 files changed, 1170 insertions(+), 1038 deletions(-) diff --git a/src/actor.h b/src/actor.h index 6e8af2498..c16080f79 100644 --- a/src/actor.h +++ b/src/actor.h @@ -538,7 +538,7 @@ int StoreDropItemChain(FDropItem *chain); // Map Object definition. class AActor : public DThinker { - DECLARE_CLASS (AActor, DThinker) + DECLARE_CLASS_WITH_META (AActor, DThinker, PClassActor) HAS_OBJECT_POINTERS public: AActor () throw(); @@ -549,7 +549,7 @@ public: void Serialize (FArchive &arc); - static AActor *StaticSpawn (const PClass *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement, bool SpawningMapThing = false); + static AActor *StaticSpawn (PClassActor *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement, bool SpawningMapThing = false); inline AActor *GetDefault () const { @@ -648,7 +648,7 @@ public: bool CheckLocalView (int playernum) const; // Finds the first item of a particular type. - AInventory *FindInventory (const PClass *type); + AInventory *FindInventory (PClassActor *type); AInventory *FindInventory (FName type); template<class T> T *FindInventory () { @@ -900,13 +900,13 @@ public: FState *FindState (FName label) const { - return GetClass()->ActorInfo->FindState(1, &label); + return GetClass()->FindState(1, &label); } FState *FindState (FName label, FName sublabel, bool exact = false) const { FName names[] = { label, sublabel }; - return GetClass()->ActorInfo->FindState(2, names, exact); + return GetClass()->FindState(2, names, exact); } bool HasSpecialDeathStates () const; @@ -975,9 +975,16 @@ public: } }; +inline AActor *Spawn (PClass *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement) +{ + return AActor::StaticSpawn (dyn_cast<PClassActor>(type), x, y, z, allowreplacement); +} + inline AActor *Spawn (const PClass *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement) { - return AActor::StaticSpawn (type, x, y, z, allowreplacement); + // Thanks to some fiddling while determining replacements, type is modified, but only + // temporarily. + return AActor::StaticSpawn (const_cast<PClassActor *>(dyn_cast<PClassActor>(type)), x, y, z, allowreplacement); } AActor *Spawn (const char *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement); diff --git a/src/b_bot.cpp b/src/b_bot.cpp index 3911264cd..8a64e2366 100644 --- a/src/b_bot.cpp +++ b/src/b_bot.cpp @@ -168,7 +168,7 @@ void InitBotStuff() { w->MoveCombatDist = botinits[i].movecombatdist; w->WeaponFlags |= botinits[i].weaponflags; - w->ProjectileType = PClass::FindClass(botinits[i].projectile); + w->ProjectileType = PClass::FindActor(botinits[i].projectile); } } } diff --git a/src/b_think.cpp b/src/b_think.cpp index 742c33a8a..1b6157246 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -354,7 +354,7 @@ void FCajunMaster::WhatToGet (AActor *actor, AActor *item) else if (item->IsKindOf (RUNTIME_CLASS(AAmmo))) { AAmmo *ammo = static_cast<AAmmo *> (item); - const PClass *parent = ammo->GetParentAmmo (); + PClassActor *parent = ammo->GetParentAmmo (); AInventory *holdingammo = b->mo->FindInventory (parent); if (holdingammo != NULL && holdingammo->Amount >= holdingammo->MaxAmount) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 4c2e7e5a0..fd2d23514 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -110,7 +110,7 @@ struct StateMapper { FState *State; int StateSpan; - const PClass *Owner; + PClassActor *Owner; bool OwnerIsPickup; }; @@ -121,7 +121,7 @@ static TArray<StateMapper> StateMap; static TArray<FSoundID> SoundMap; // Names of different actor types, in original Doom 2 order -static TArray<const PClass *> InfoNames; +static TArray<PClassActor *> InfoNames; // bit flags for PatchThing (a .bex extension): struct BitName @@ -142,8 +142,8 @@ struct StyleName static TArray<StyleName> StyleNames; -static TArray<const PClass *> AmmoNames; -static TArray<const PClass *> WeaponNames; +static TArray<PClassActor *> AmmoNames; +static TArray<PClassActor *> WeaponNames; // DeHackEd trickery to support MBF-style parameters // List of states that are hacked to use a codepointer @@ -196,7 +196,7 @@ IMPLEMENT_POINTY_CLASS (ADehackedPickup) DECLARE_POINTER (RealPickup) END_POINTERS -TArray<PClass *> TouchedActors; +TArray<PClassActor *> TouchedActors; char *UnchangedSpriteNames; int NumUnchangedSprites; @@ -318,11 +318,14 @@ static bool ReadChars (char **stuff, int size); static char *igets (void); static int GetLine (void); -static void PushTouchedActor(PClass *cls) +static void PushTouchedActor(PClassActor *cls) { for(unsigned i = 0; i < TouchedActors.Size(); i++) { - if (TouchedActors[i] == cls) return; + if (TouchedActors[i] == cls) + { + return; + } } TouchedActors.Push(cls); } @@ -390,7 +393,7 @@ static FState *FindState (int statenum) { if (StateMap[i].OwnerIsPickup) { - PushTouchedActor(const_cast<PClass *>(StateMap[i].Owner)); + PushTouchedActor(StateMap[i].Owner); } return StateMap[i].State + statenum - stateacc; } @@ -746,7 +749,7 @@ static int PatchThing (int thingy) FStateDefinitions statedef; bool patchedStates = false; int oldflags; - const PClass *type; + PClassActor *type; SWORD *ednum, dummyed; type = NULL; @@ -772,7 +775,7 @@ static int PatchThing (int thingy) else { info = GetDefaultByType (type); - ednum = &type->ActorInfo->DoomEdNum; + ednum = &type->DoomEdNum; } } } @@ -1179,7 +1182,7 @@ static int PatchThing (int thingy) if (info->flags & MF_SPECIAL) { - PushTouchedActor(const_cast<PClass *>(type)); + PushTouchedActor(const_cast<PClassActor *>(type)); } // Make MF3_ISMONSTER match MF_COUNTKILL @@ -1193,7 +1196,7 @@ static int PatchThing (int thingy) } if (patchedStates) { - statedef.InstallStates(type->ActorInfo, info); + statedef.InstallStates(type, info); } } @@ -1486,7 +1489,7 @@ static int PatchAmmo (int ammoNum) static int PatchWeapon (int weapNum) { int result; - const PClass *type = NULL; + PClassActor *type = NULL; BYTE dummy[sizeof(AWeapon)]; AWeapon *info = (AWeapon *)&dummy; bool patchedStates = false; @@ -1589,7 +1592,7 @@ static int PatchWeapon (int weapNum) if (patchedStates) { - statedef.InstallStates(type->ActorInfo, info); + statedef.InstallStates(type, info); } return result; @@ -1764,14 +1767,14 @@ static int PatchMisc (int dummy) }; static const PClass * const *types[] = { - &RUNTIME_CLASS(APowerInvulnerable), - &RUNTIME_CLASS(APowerStrength), - &RUNTIME_CLASS(APowerInvisibility), - &RUNTIME_CLASS(APowerIronFeet), - &RUNTIME_CLASS(APowerLightAmp), - &RUNTIME_CLASS(APowerWeaponLevel2), - &RUNTIME_CLASS(APowerSpeed), - &RUNTIME_CLASS(APowerMinotaur) + &RUNTIME_CLASS_CASTLESS(APowerInvulnerable), + &RUNTIME_CLASS_CASTLESS(APowerStrength), + &RUNTIME_CLASS_CASTLESS(APowerInvisibility), + &RUNTIME_CLASS_CASTLESS(APowerIronFeet), + &RUNTIME_CLASS_CASTLESS(APowerLightAmp), + &RUNTIME_CLASS_CASTLESS(APowerWeaponLevel2), + &RUNTIME_CLASS_CASTLESS(APowerSpeed), + &RUNTIME_CLASS_CASTLESS(APowerMinotaur) }; int i; @@ -2657,19 +2660,20 @@ static bool LoadDehSupp () StateMapper s; sc.MustGetString(); - const PClass *type = PClass::FindClass (sc.String); + PClass *type = PClass::FindClass (sc.String); if (type == NULL) { sc.ScriptError ("Can't find type %s", sc.String); } - else if (type->ActorInfo == NULL) + else if (!type->IsKindOf(RUNTIME_CLASS(PClassActor))) { - sc.ScriptError ("%s has no ActorInfo", sc.String); + sc.ScriptError ("%s is not an actor", sc.String); } sc.MustGetStringName(","); sc.MustGetString(); - s.State = type->ActorInfo->FindState(sc.String); + PClassActor *actortype = static_cast<PClassActor *>(type); + s.State = actortype->FindState(sc.String); if (s.State == NULL) { sc.ScriptError("Invalid state '%s' in '%s'", sc.String, type->TypeName.GetChars()); @@ -2677,14 +2681,14 @@ static bool LoadDehSupp () sc.MustGetStringName(","); sc.MustGetNumber(); - if (s.State == NULL || s.State + sc.Number > type->ActorInfo->OwnedStates + type->ActorInfo->NumOwnedStates) + if (s.State == NULL || s.State + sc.Number > actortype->OwnedStates + actortype->NumOwnedStates) { sc.ScriptError("Invalid state range in '%s'", type->TypeName.GetChars()); } AActor *def = GetDefaultByType(type); s.StateSpan = sc.Number; - s.Owner = type; + s.Owner = actortype; s.OwnerIsPickup = def != NULL && (def->flags & MF_SPECIAL) != 0; if (addit) StateMap.Push(s); @@ -2709,7 +2713,7 @@ static bool LoadDehSupp () while (!sc.CheckString("}")) { sc.MustGetString(); - const PClass *cls = PClass::FindClass(sc.String); + PClassActor *cls = PClass::FindActor(sc.String); if (cls == NULL) { sc.ScriptError("Unknown actor type '%s'", sc.String); @@ -2776,12 +2780,12 @@ static bool LoadDehSupp () } else { - const PClass *cls = PClass::FindClass(sc.String); + PClass *cls = PClass::FindClass(sc.String); if (cls == NULL || cls->ParentClass != RUNTIME_CLASS(AAmmo)) { sc.ScriptError("Unknown ammo type '%s'", sc.String); } - AmmoNames.Push(cls); + AmmoNames.Push(static_cast<PClassActor *>(cls)); } if (sc.CheckString("}")) break; sc.MustGetStringName(","); @@ -2793,12 +2797,12 @@ static bool LoadDehSupp () while (!sc.CheckString("}")) { sc.MustGetString(); - const PClass *cls = PClass::FindClass(sc.String); + PClass *cls = PClass::FindClass(sc.String); if (cls == NULL || !cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { sc.ScriptError("Unknown weapon type '%s'", sc.String); } - WeaponNames.Push(cls); + WeaponNames.Push(static_cast<PClassActor *>(cls)); if (sc.CheckString("}")) break; sc.MustGetStringName(","); } @@ -2848,7 +2852,7 @@ void FinishDehPatch () for (touchedIndex = 0; touchedIndex < TouchedActors.Size(); ++touchedIndex) { - PClass *type = TouchedActors[touchedIndex]; + PClassActor *type = TouchedActors[touchedIndex]; AActor *defaults1 = GetDefaultByType (type); if (!(defaults1->flags & MF_SPECIAL)) { // We only need to do this for pickups @@ -2858,8 +2862,8 @@ void FinishDehPatch () // Create a new class that will serve as the actual pickup char typeNameBuilder[32]; mysnprintf (typeNameBuilder, countof(typeNameBuilder), "DehackedPickup%d", touchedIndex); - PClass *subclass = RUNTIME_CLASS(ADehackedPickup)->CreateDerivedClass - (typeNameBuilder, sizeof(ADehackedPickup)); + PClassActor *subclass = static_cast<PClassActor *>(RUNTIME_CLASS(ADehackedPickup)-> + CreateDerivedClass(typeNameBuilder, sizeof(ADehackedPickup))); AActor *defaults2 = GetDefaultByType (subclass); memcpy (defaults2, defaults1, sizeof(AActor)); @@ -2870,21 +2874,21 @@ void FinishDehPatch () if (!type->IsDescendantOf(RUNTIME_CLASS(AInventory))) { // If this is a hacked non-inventory item we must also copy AInventory's special states - statedef.AddStateDefines(RUNTIME_CLASS(AInventory)->ActorInfo->StateList); + statedef.AddStateDefines(RUNTIME_CLASS(AInventory)->StateList); } - statedef.InstallStates(subclass->ActorInfo, defaults2); + statedef.InstallStates(subclass, defaults2); // Use the DECORATE replacement feature to redirect all spawns // of the original class to the new one. - FActorInfo *old_replacement = type->ActorInfo->Replacement; + PClassActor *old_replacement = type->Replacement; - type->ActorInfo->Replacement = subclass->ActorInfo; - subclass->ActorInfo->Replacee = type->ActorInfo; + type->Replacement = subclass; + subclass->Replacee = type; // If this actor was already replaced by another actor, copy that // replacement over to this item. if (old_replacement != NULL) { - subclass->ActorInfo->Replacement = old_replacement; + subclass->Replacement = old_replacement; } DPrintf ("%s replaces %s\n", subclass->TypeName.GetChars(), type->TypeName.GetChars()); diff --git a/src/d_main.cpp b/src/d_main.cpp index 4b3d4fcb0..0a59d05f4 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2055,7 +2055,7 @@ void D_DoomMain (void) Printf ("ParseTeamInfo: Load team definitions.\n"); TeamLibrary.ParseTeamInfo (); - FActorInfo::StaticInit (); + PClassActor::StaticInit (); // [GRB] Initialize player class list SetupPlayerClasses (); @@ -2105,7 +2105,7 @@ void D_DoomMain (void) // Create replacements for dehacked pickups FinishDehPatch(); - FActorInfo::StaticSetActorNums (); + PClassActor::StaticSetActorNums (); // [RH] User-configurable startup strings. Because BOOM does. static const char *startupString[5] = { diff --git a/src/d_net.cpp b/src/d_net.cpp index 264aed1df..6c874f7b9 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2115,7 +2115,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) } typeinfo = PClass::FindClass (s); - if (typeinfo != NULL && typeinfo->ActorInfo != NULL) + if (typeinfo != NULL && typeinfo->IsKindOf(RUNTIME_CLASS(PClassActor))) { AActor *source = players[player].mo; if (source != NULL) @@ -2383,7 +2383,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) } for(int i = 0; i < count; ++i) { - const PClass *wpn = Net_ReadWeapon(stream); + PClassActor *wpn = Net_ReadWeapon(stream); players[player].weapons.AddSlot(slot, wpn, player == consoleplayer); } } @@ -2392,7 +2392,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_ADDSLOT: { int slot = ReadByte(stream); - const PClass *wpn = Net_ReadWeapon(stream); + PClassActor *wpn = Net_ReadWeapon(stream); players[player].weapons.AddSlot(slot, wpn, player == consoleplayer); } break; @@ -2400,7 +2400,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_ADDSLOTDEFAULT: { int slot = ReadByte(stream); - const PClass *wpn = Net_ReadWeapon(stream); + PClassActor *wpn = Net_ReadWeapon(stream); players[player].weapons.AddSlotDefault(slot, wpn, player == consoleplayer); } break; diff --git a/src/decallib.cpp b/src/decallib.cpp index d20adc921..6446f9283 100644 --- a/src/decallib.cpp +++ b/src/decallib.cpp @@ -598,7 +598,7 @@ void FDecalLib::ParseGenerator (FScanner &sc) // Get name of generator (actor) sc.MustGetString (); type = PClass::FindClass (sc.String); - if (type == NULL || type->ActorInfo == NULL) + if (type == NULL || !type->IsKindOf(RUNTIME_CLASS(PClassActor))) { sc.ScriptError ("%s is not an actor.", sc.String); } diff --git a/src/dobject.cpp b/src/dobject.cpp index bb4c0d04b..f34a577bb 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -53,9 +53,10 @@ ClassReg DObject::RegistrationInfo = NULL, // MyClass "DObject", // Name NULL, // ParentType - sizeof(DObject), // SizeOf NULL, // Pointers - &DObject::InPlaceConstructor // ConstructNative + &DObject::InPlaceConstructor, // ConstructNative + sizeof(DObject), // SizeOf + CLASSREG_PClass, // MetaClassNum }; _DECLARE_TI(DObject) @@ -294,7 +295,6 @@ CCMD (dumpclasses) int shown, omitted; DumpInfo *tree = NULL; const PClass *root = NULL; - bool showall = true; if (argv.argc() > 1) { @@ -304,13 +304,6 @@ CCMD (dumpclasses) Printf ("Class '%s' not found\n", argv[1]); return; } - if (stricmp (argv[1], "Actor") == 0) - { - if (argv.argc() < 3 || stricmp (argv[2], "all") != 0) - { - showall = false; - } - } } shown = omitted = 0; @@ -318,10 +311,7 @@ CCMD (dumpclasses) for (i = 0; i < PClass::m_Types.Size(); i++) { PClass *cls = PClass::m_Types[i]; - if (root == NULL || - (cls->IsDescendantOf (root) && - (showall || cls == root || - cls->ActorInfo != root->ActorInfo))) + if (root == NULL || cls == root || cls->IsDescendantOf(root)) { DumpInfo::AddType (&tree, cls); // Printf (" %s\n", PClass::m_Types[i]->Name + 1); diff --git a/src/dobject.h b/src/dobject.h index fb0d30f7c..5b6d99e46 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -78,7 +78,7 @@ class DFloorWaggle; class DPlat; class DPillar; -struct FActorInfo; +class PClassActor; enum EMetaType { @@ -130,18 +130,27 @@ private: void CopyMeta (const FMetaTable *other); }; -#define RUNTIME_TYPE(object) (object->GetClass()) // Passed an object, returns the type of that object -#define RUNTIME_CLASS(cls) (cls::RegistrationInfo.MyClass) // Passed a native class name, returns a PClass representing that class -#define NATIVE_TYPE(object) (object->StaticType()) // Passed an object, returns the type of the C++ class representing the object +#define RUNTIME_TYPE(object) (object->GetClass()) // Passed an object, returns the type of that object +#define RUNTIME_CLASS_CASTLESS(cls) (cls::RegistrationInfo.MyClass) // Passed a native class name, returns a PClass representing that class +#define RUNTIME_CLASS(cls) ((cls::MetaClass *)RUNTIME_CLASS_CASTLESS(cls)) // Like above, but returns the true type of the meta object +#define NATIVE_TYPE(object) (object->StaticType()) // Passed an object, returns the type of the C++ class representing the object + +// Enumerations for the meta classes created by ClassReg::RegisterClass() +enum +{ + CLASSREG_PClass, + CLASSREG_PClassActor, +}; struct ClassReg { PClass *MyClass; const char *Name; ClassReg *ParentType; - unsigned int SizeOf; const size_t *Pointers; void (*ConstructNative)(void *); + unsigned int SizeOf:31; + unsigned int MetaClassNum:1; PClass *RegisterClass(); }; @@ -156,10 +165,22 @@ private: \ typedef parent Super; \ typedef cls ThisClass; +#define DECLARE_ABSTRACT_CLASS_WITH_META(cls,parent,meta) \ + DECLARE_ABSTRACT_CLASS(cls,parent) \ +public: \ + typedef meta MetaClass; \ + MetaClass *GetClass() const { return static_cast<MetaClass *>(DObject::GetClass()); } \ +protected: \ + enum { MetaClassNum = CLASSREG_##meta }; private: \ + #define DECLARE_CLASS(cls,parent) \ DECLARE_ABSTRACT_CLASS(cls,parent) \ private: static void InPlaceConstructor (void *mem); +#define DECLARE_CLASS_WITH_META(cls,parent,meta) \ + DECLARE_ABSTRACT_CLASS_WITH_META(cls,parent,meta) \ + private: static void InPlaceConstructor (void *mem); + #define HAS_OBJECT_POINTERS \ static const size_t PointerOffsets[]; @@ -180,9 +201,10 @@ private: \ NULL, \ #cls, \ &cls::Super::RegistrationInfo, \ - sizeof(cls), \ ptrs, \ - create }; \ + create, \ + sizeof(cls), \ + cls::MetaClassNum }; \ _DECLARE_TI(cls) #define _IMP_CREATE_OBJ(cls) \ @@ -436,8 +458,11 @@ public: virtual PClass *StaticType() const { return RegistrationInfo.MyClass; } static ClassReg RegistrationInfo, * const RegistrationInfoPtr; static void InPlaceConstructor (void *mem); + typedef PClass MetaClass; private: typedef DObject ThisClass; +protected: + enum { MetaClassNum = CLASSREG_PClass }; // Per-instance variables. There are four. private: @@ -592,4 +617,18 @@ inline bool DObject::IsA (const PClass *type) const return (type == GetClass()); } +template<class T> T *dyn_cast(DObject *p) +{ + if (p != NULL && p->IsKindOf(RUNTIME_CLASS_CASTLESS(T))) + { + return static_cast<T *>(p); + } + return NULL; +} + +template<class T> const T *dyn_cast(const DObject *p) +{ + return dyn_cast<T>(const_cast<DObject *>(p)); +} + #endif //__DOBJECT_H__ diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 0e2e26aac..e0a4a0239 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -43,7 +43,7 @@ IMPLEMENT_POINTY_CLASS(PClass) DECLARE_POINTER(ParentClass) END_POINTERS -TArray<PClass *> PClass::m_RuntimeActors; +TArray<PClassActor *> PClass::m_RuntimeActors; TArray<PClass *> PClass::m_Types; PClass *PClass::TypeHash[PClass::HASH_SIZE]; bool PClass::bShutdown; @@ -103,8 +103,6 @@ void PClass::StaticShutdown () uniqueFPs.Push(const_cast<size_t *>(type->FlatPointers)); } } - // For runtime classes, this call will also delete the PClass. - PClass::StaticFreeData (type); } for (i = 0; i < uniqueFPs.Size(); ++i) { @@ -119,7 +117,6 @@ PClass::PClass() ParentClass = NULL; Pointers = NULL; FlatPointers = NULL; - ActorInfo = NULL; HashNext = NULL; Defaults = NULL; bRuntimeClass = false; @@ -129,45 +126,11 @@ PClass::PClass() PClass::~PClass() { Symbols.ReleaseSymbols(); -} - -void PClass::StaticFreeData (PClass *type) -{ - if (type->Defaults != NULL) + if (Defaults != NULL) { - M_Free(type->Defaults); - type->Defaults = NULL; + M_Free(Defaults); + Defaults = NULL; } - type->FreeStateList (); - - if (type->ActorInfo != NULL) - { - if (type->ActorInfo->OwnedStates != NULL) - { - delete[] type->ActorInfo->OwnedStates; - type->ActorInfo->OwnedStates = NULL; - } - if (type->ActorInfo->DamageFactors != NULL) - { - delete type->ActorInfo->DamageFactors; - type->ActorInfo->DamageFactors = NULL; - } - if (type->ActorInfo->PainChances != NULL) - { - delete type->ActorInfo->PainChances; - type->ActorInfo->PainChances = NULL; - } - delete type->ActorInfo; - type->ActorInfo = NULL; - }/* - if (type->bRuntimeClass) - { - delete type; - } - else - { - type->Symbols.ReleaseSymbols(); - }*/ } PClass *ClassReg::RegisterClass() @@ -180,7 +143,21 @@ PClass *ClassReg::RegisterClass() } // Add type to list - PClass *cls = new PClass; + PClass *cls; + + switch (MetaClassNum) + { + case CLASSREG_PClass: + cls = new PClass; + break; + + case CLASSREG_PClassActor: + cls = new PClassActor; + break; + + default: + assert(0 && "Class registry has an invalid meta class identifier"); + } MyClass = cls; PClass::m_Types.Push(cls); cls->TypeName = FName(Name+1); @@ -292,7 +269,8 @@ PClass *PClass::CreateDerivedClass (FName name, unsigned int size) } else { - type = new PClass; + // Create a new type object of the same type as us. (We may be a derived class of PClass.) + type = static_cast<PClass *>(GetClass()->CreateNew()); notnew = false; } @@ -317,27 +295,17 @@ PClass *PClass::CreateDerivedClass (FName name, unsigned int size) type->FlatPointers = NULL; type->bRuntimeClass = true; - type->ActorInfo = NULL; type->Symbols.SetParentTable (&this->Symbols); - if (!notnew) type->InsertIntoHash(); + if (!notnew) + { + type->InsertIntoHash(); + } // If this class has an actor info, then any classes derived from it // also need an actor info. - if (this->ActorInfo != NULL) + if (type->IsKindOf(RUNTIME_CLASS(PClassActor))) { - FActorInfo *info = type->ActorInfo = new FActorInfo; - info->Class = type; - info->GameFilter = GAME_Any; - info->SpawnID = 0; - info->DoomEdNum = -1; - info->OwnedStates = NULL; - info->NumOwnedStates = 0; - info->Replacement = NULL; - info->Replacee = NULL; - info->StateList = NULL; - info->DamageFactors = NULL; - info->PainChances = NULL; - m_RuntimeActors.Push (type); + m_RuntimeActors.Push(static_cast<PClassActor *>(type)); } return type; } @@ -358,7 +326,7 @@ unsigned int PClass::Extend(unsigned int extension) // Like FindClass but creates a placeholder if no class // is found. CreateDerivedClass will automatcally fill in // the placeholder when the actual class is defined. -const PClass *PClass::FindClassTentative (FName name) +PClass *PClass::FindClassTentative (FName name) { if (name == NAME_None) { @@ -383,7 +351,7 @@ const PClass *PClass::FindClassTentative (FName name) break; } } - PClass *type = new PClass; + PClass *type = new PClassActor; DPrintf("Creating placeholder class %s : %s\n", name.GetChars(), TypeName.GetChars()); type->TypeName = name; @@ -395,45 +363,10 @@ const PClass *PClass::FindClassTentative (FName name) type->Defaults = NULL; type->FlatPointers = NULL; type->bRuntimeClass = true; - type->ActorInfo = NULL; type->InsertIntoHash(); return type; } -// This is used by DECORATE to assign ActorInfos to internal classes -void PClass::InitializeActorInfo () -{ - Symbols.SetParentTable (&ParentClass->Symbols); - Defaults = new BYTE[Size]; - if (ParentClass->Defaults != NULL) - { - memcpy (Defaults, ParentClass->Defaults, ParentClass->Size); - if (Size > ParentClass->Size) - { - memset (Defaults + ParentClass->Size, 0, Size - ParentClass->Size); - } - } - else - { - memset (Defaults, 0, Size); - } - - FActorInfo *info = ActorInfo = new FActorInfo; - info->Class = this; - info->GameFilter = GAME_Any; - info->SpawnID = 0; - info->DoomEdNum = -1; - info->OwnedStates = NULL; - info->NumOwnedStates = 0; - info->Replacement = NULL; - info->Replacee = NULL; - info->StateList = NULL; - info->DamageFactors = NULL; - info->PainChances = NULL; - m_RuntimeActors.Push (this); -} - - // Create the FlatPointers array, if it doesn't exist already. // It comprises all the Pointers from superclasses plus this class's own Pointers. // If this class does not define any new Pointers, then FlatPointers will be set @@ -485,16 +418,6 @@ void PClass::BuildFlatPointers () } } -void PClass::FreeStateList () -{ - if (ActorInfo != NULL && ActorInfo->StateList != NULL) - { - ActorInfo->StateList->Destroy(); - M_Free (ActorInfo->StateList); - ActorInfo->StateList = NULL; - } -} - const PClass *PClass::NativeClass() const { const PClass *cls = this; @@ -512,18 +435,6 @@ size_t PClass::PropagateMark() // Mark symbols marked = Symbols.MarkSymbols(); - // Mark state functions - if (ActorInfo != NULL) - { - for (int i = 0; i < ActorInfo->NumOwnedStates; ++i) - { - if (ActorInfo->OwnedStates[i].ActionFunc != NULL) - { - GC::Mark(ActorInfo->OwnedStates[i].ActionFunc); - } - } -// marked += ActorInfo->NumOwnedStates * sizeof(FState); - } return marked + Super::PropagateMark(); } diff --git a/src/dobjtype.h b/src/dobjtype.h index 264aaf11c..091ec47ac 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -156,7 +156,6 @@ class PClass : public DObject public: static void StaticInit (); static void StaticShutdown (); - static void StaticFreeData (PClass *type); // Per-class information ------------------------------------- FName TypeName; // this class's name @@ -164,7 +163,6 @@ public: PClass *ParentClass; // the class this class derives from const size_t *Pointers; // object pointers defined by this class *only* const size_t *FlatPointers; // object pointers defined by this class and all its superclasses; not initialized by default - FActorInfo *ActorInfo; PClass *HashNext; FMetaTable Meta; BYTE *Defaults; @@ -183,7 +181,6 @@ public: unsigned int Extend(unsigned int extension); void InitializeActorInfo (); void BuildFlatPointers (); - void FreeStateList(); const PClass *NativeClass() const; size_t PropagateMark(); @@ -208,10 +205,14 @@ public: static PClass *FindClass (const FString &name) { return FindClass (FName (name, true)); } static PClass *FindClass (ENamedName name) { return FindClass (FName (name)); } static PClass *FindClass (FName name); - const PClass *FindClassTentative (FName name); // not static! + static PClassActor *FindActor (const char *name) { return FindActor (FName (name, true)); } + static PClassActor *FindActor (const FString &name) { return FindActor (FName (name, true)); } + static PClassActor *FindActor (ENamedName name) { return FindActor (FName (name)); } + static PClassActor *FindActor (FName name); + PClass *FindClassTentative (FName name); // not static! static TArray<PClass *> m_Types; - static TArray<PClass *> m_RuntimeActors; + static TArray<PClassActor *> m_RuntimeActors; enum { HASH_SIZE = 256 }; static PClass *TypeHash[HASH_SIZE]; diff --git a/src/f_finale.cpp b/src/f_finale.cpp index e08f249eb..9b8694d6f 100644 --- a/src/f_finale.cpp +++ b/src/f_finale.cpp @@ -464,10 +464,10 @@ void F_TextWrite (void) // struct castinfo_t { - const char *name; - const char *type; - const AActor *info; - const PClass *Class; + const char *name; + const char *type; + const AActor *info; + const PClassActor *Class; }; castinfo_t castorder[] = @@ -566,7 +566,7 @@ void F_StartCast (void) else { castorder[i].info = GetDefaultByType (type); - castorder[i].Class= type; + castorder[i].Class= dyn_cast<PClassActor>(type); } } @@ -729,7 +729,7 @@ bool F_CastResponder (event_t* ev) // go into death frame castdeath = true; - caststate = castorder[castnum].Class->ActorInfo->FindState(NAME_Death); + caststate = castorder[castnum].Class->FindState(NAME_Death); if (caststate != NULL) { casttics = caststate->GetTics(); diff --git a/src/farchive.h b/src/farchive.h index 9af7d25ba..31a0358e8 100644 --- a/src/farchive.h +++ b/src/farchive.h @@ -169,6 +169,12 @@ virtual void Read (void *mem, unsigned int len); void UserWriteClass (const PClass *info); void UserReadClass (const PClass *&info); + template<typename T> void UserReadClass(const T *&info) + { + const PClass *myclass; + UserReadClass(myclass); + info = dyn_cast<T>(const_cast<PClass *>(myclass)); + } FArchive& operator<< (BYTE &c); FArchive& operator<< (WORD &s); diff --git a/src/g_doom/a_archvile.cpp b/src/g_doom/a_archvile.cpp index 88fd5f565..4b892ed63 100644 --- a/src/g_doom/a_archvile.cpp +++ b/src/g_doom/a_archvile.cpp @@ -85,7 +85,7 @@ void A_Fire(AActor *self, int height) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileTarget) { PARAM_ACTION_PROLOGUE; - PARAM_CLASS_OPT(fire, AActor) { fire = PClass::FindClass("ArchvileFire"); } + PARAM_CLASS_OPT(fire, AActor) { fire = PClass::FindActor("ArchvileFire"); } AActor *fog; diff --git a/src/g_doom/a_bossbrain.cpp b/src/g_doom/a_bossbrain.cpp index 38e90c19a..9e97f39dc 100644 --- a/src/g_doom/a_bossbrain.cpp +++ b/src/g_doom/a_bossbrain.cpp @@ -39,13 +39,12 @@ static void BrainishExplosion (fixed_t x, fixed_t y, fixed_t z) boom->DeathSound = "misc/brainexplode"; boom->velz = pr_brainscream() << 9; - const PClass *cls = PClass::FindClass("BossBrain"); + PClassActor *cls = PClass::FindActor("BossBrain"); if (cls != NULL) { - FState *state = cls->ActorInfo->FindState(NAME_Brainexplode); + FState *state = cls->FindState(NAME_Brainexplode); if (state != NULL) boom->SetState (state); - } boom->effects = 0; boom->Damage = 0; // disables collision detection which is not wanted here @@ -107,7 +106,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BrainSpit) { if (spawntype == NULL) { - spawntype = PClass::FindClass("SpawnShot"); + spawntype = PClass::FindActor("SpawnShot"); isdefault = true; } @@ -282,7 +281,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnFly) } else { - spawntype = PClass::FindClass("SpawnFire"); + spawntype = PClass::FindActor("SpawnFire"); sound = "brain/spawn"; } SpawnFly(self, spawntype, sound); diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index 7577b1515..f7754fa86 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -98,7 +98,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePistol) S_Sound (self, CHAN_WEAPON, "weapons/pistol", 1, ATTN_NORM); - P_GunShot (self, accurate, PClass::FindClass(NAME_BulletPuff), P_BulletSlope (self)); + P_GunShot (self, accurate, PClass::FindActor(NAME_BulletPuff), P_BulletSlope (self)); return 0; } @@ -130,9 +130,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) } if (pufftype == NULL) - pufftype = PClass::FindClass(NAME_BulletPuff); + { + pufftype = PClass::FindActor(NAME_BulletPuff); + } if (damage == 0) + { damage = 2; + } damage *= (pr_saw()%10 + 1); angle = self->angle; @@ -198,8 +202,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun) angle_t pitch = P_BulletSlope (self); - for (i=0 ; i<7 ; i++) - P_GunShot (self, false, PClass::FindClass(NAME_BulletPuff), pitch); + for (i = 0; i < 7; i++) + { + P_GunShot (self, false, PClass::FindActor(NAME_BulletPuff), pitch); + } return 0; } @@ -286,18 +292,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_CloseShotgun2) // //------------------------------------------------------------------------------------ -void P_SetSafeFlash(AWeapon * weapon, player_t * player, FState * flashstate, int index) +void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int index) { - const PClass * cls = weapon->GetClass(); + PClassActor *cls = weapon->GetClass(); while (cls != RUNTIME_CLASS(AWeapon)) { - FActorInfo * info = cls->ActorInfo; - if (flashstate >= info->OwnedStates && flashstate < info->OwnedStates + info->NumOwnedStates) + if (flashstate >= cls->OwnedStates && flashstate < cls->OwnedStates + cls->NumOwnedStates) { // The flash state belongs to this class. // Now let's check if the actually wanted state does also - if (flashstate+index < info->OwnedStates + info->NumOwnedStates) + if (flashstate + index < cls->OwnedStates + cls->NumOwnedStates) { // we're ok so set the state P_SetPsprite (player, ps_flash, flashstate + index); @@ -311,7 +316,7 @@ void P_SetSafeFlash(AWeapon * weapon, player_t * player, FState * flashstate, in } } // try again with parent class - cls = cls->ParentClass; + cls = static_cast<PClassActor *>(cls->ParentClass); } // if we get here the state doesn't seem to belong to any class in the inheritance chain // This can happen with Dehacked if the flash states are remapped. @@ -362,7 +367,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireCGun) } player->mo->PlayAttacking2 (); - P_GunShot (self, !player->refire, PClass::FindClass(NAME_BulletPuff), P_BulletSlope (self)); + P_GunShot (self, !player->refire, PClass::FindActor(NAME_BulletPuff), P_BulletSlope (self)); return 0; } @@ -395,7 +400,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMissile) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireSTGrenade) { PARAM_ACTION_PROLOGUE; - PARAM_CLASS_OPT(grenade, AActor) { grenade = PClass::FindClass("Grenade"); } + PARAM_CLASS_OPT(grenade, AActor) { grenade = PClass::FindActor("Grenade"); } player_t *player; @@ -555,7 +560,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray) AActor *linetarget; - if (spraytype == NULL) spraytype = PClass::FindClass("BFGExtra"); + if (spraytype == NULL) spraytype = PClass::FindActor("BFGExtra"); if (numrays <= 0) numrays = 40; if (damagecnt <= 0) damagecnt = 15; diff --git a/src/g_doom/a_fatso.cpp b/src/g_doom/a_fatso.cpp index a147101d3..2d55b49c7 100644 --- a/src/g_doom/a_fatso.cpp +++ b/src/g_doom/a_fatso.cpp @@ -37,7 +37,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FatAttack1) if (!self->target) return 0; - if (spawntype == NULL) spawntype = PClass::FindClass("FatShot"); + if (spawntype == NULL) spawntype = PClass::FindActor("FatShot"); A_FaceTarget (self); // Change direction to ... @@ -66,7 +66,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FatAttack2) if (!self->target) return 0; - if (spawntype == NULL) spawntype = PClass::FindClass("FatShot"); + if (spawntype == NULL) spawntype = PClass::FindActor("FatShot"); A_FaceTarget (self); // Now here choose opposite deviation. @@ -95,7 +95,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FatAttack3) if (!self->target) return 0; - if (spawntype == NULL) spawntype = PClass::FindClass("FatShot"); + if (spawntype == NULL) spawntype = PClass::FindActor("FatShot"); A_FaceTarget (self); @@ -144,8 +144,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Mushroom) int i, j; - if (n == 0) n = self->Damage; // GetMissileDamage (0, 1); - if (spawntype == NULL) spawntype = PClass::FindClass("FatShot"); + if (n == 0) + { + n = self->Damage; // GetMissileDamage (0, 1); + } + if (spawntype == NULL) + { + spawntype = PClass::FindActor("FatShot"); + } P_RadiusAttack (self, self->target, 128, 128, self->DamageType, !(flags & MSF_DontHurt)); P_CheckSplash(self, 128<<FRACBITS); diff --git a/src/g_doom/a_scriptedmarine.cpp b/src/g_doom/a_scriptedmarine.cpp index 34d7b5470..ffaae7eec 100644 --- a/src/g_doom/a_scriptedmarine.cpp +++ b/src/g_doom/a_scriptedmarine.cpp @@ -263,8 +263,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Saw) if (self->target == NULL) return 0; - if (pufftype == NULL) pufftype = PClass::FindClass(NAME_BulletPuff); - if (damage == 0) damage = 2; + if (pufftype == NULL) + { + pufftype = PClass::FindActor(NAME_BulletPuff); + } + if (damage == 0) + { + damage = 2; + } A_FaceTarget (self); if (self->CheckMeleeRange ()) @@ -357,7 +363,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Punch) // //============================================================================ -void P_GunShot2 (AActor *mo, bool accurate, int pitch, const PClass *pufftype) +void P_GunShot2 (AActor *mo, bool accurate, int pitch, PClassActor *pufftype) { angle_t angle; int damage; @@ -390,7 +396,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_FirePistol) S_Sound (self, CHAN_WEAPON, "weapons/pistol", 1, ATTN_NORM); A_FaceTarget (self); P_GunShot2 (self, accurate, P_AimLineAttack (self, self->angle, MISSILERANGE), - PClass::FindClass(NAME_BulletPuff)); + PClass::FindActor(NAME_BulletPuff)); return 0; } @@ -414,7 +420,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_FireShotgun) pitch = P_AimLineAttack (self, self->angle, MISSILERANGE); for (int i = 0; i < 7; ++i) { - P_GunShot2 (self, false, pitch, PClass::FindClass(NAME_BulletPuff)); + P_GunShot2 (self, false, pitch, PClass::FindActor(NAME_BulletPuff)); } self->special1 = level.maptime + 27; return 0; @@ -489,7 +495,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_FireCGun) S_Sound (self, CHAN_WEAPON, "weapons/chngun", 1, ATTN_NORM); A_FaceTarget (self); P_GunShot2 (self, accurate, P_AimLineAttack (self, self->angle, MISSILERANGE), - PClass::FindClass(NAME_BulletPuff)); + PClass::FindActor(NAME_BulletPuff)); return 0; } @@ -637,9 +643,9 @@ void AScriptedMarine::SetWeapon (EMarineWeapon type) void AScriptedMarine::SetSprite (const PClass *source) { - if (source == NULL || source->ActorInfo == NULL) + if (source == NULL) { // A valid actor class wasn't passed, so use the standard sprite - SpriteOverride = sprite = GetClass()->ActorInfo->OwnedStates[0].sprite; + SpriteOverride = sprite = GetClass()->OwnedStates[0].sprite; // Copy the standard scaling scaleX = GetDefault()->scaleX; scaleY = GetDefault()->scaleY; diff --git a/src/g_game.cpp b/src/g_game.cpp index dc576c2fc..77554bb26 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -419,13 +419,16 @@ CCMD (use) { if (argv.argc() > 1 && who != NULL) { - SendItemUse = who->FindInventory (PClass::FindClass (argv[1])); + SendItemUse = who->FindInventory(PClass::FindActor(argv[1])); } } CCMD (invdrop) { - if (players[consoleplayer].mo) SendItemDrop = players[consoleplayer].mo->InvSel; + if (players[consoleplayer].mo) + { + SendItemDrop = players[consoleplayer].mo->InvSel; + } } CCMD (weapdrop) @@ -437,7 +440,7 @@ CCMD (drop) { if (argv.argc() > 1 && who != NULL) { - SendItemDrop = who->FindInventory (PClass::FindClass (argv[1])); + SendItemDrop = who->FindInventory(PClass::FindActor(argv[1])); } } @@ -476,7 +479,7 @@ CCMD (select) { if (argv.argc() > 1) { - AInventory *item = who->FindInventory (PClass::FindClass (argv[1])); + AInventory *item = who->FindInventory(PClass::FindActor(argv[1])); if (item != NULL) { who->InvSel = item; diff --git a/src/g_heretic/a_hereticmisc.cpp b/src/g_heretic/a_hereticmisc.cpp index 141dff651..cd47a1fd4 100644 --- a/src/g_heretic/a_hereticmisc.cpp +++ b/src/g_heretic/a_hereticmisc.cpp @@ -43,7 +43,7 @@ static FRandom pr_volcimpact ("VolcBallImpact"); DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PodPain) { PARAM_ACTION_PROLOGUE; - PARAM_CLASS_OPT (gootype, AActor) { gootype = PClass::FindClass("PodGoo"); } + PARAM_CLASS_OPT (gootype, AActor) { gootype = PClass::FindActor("PodGoo"); } int count; int chance; @@ -98,7 +98,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RemovePod) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MakePod) { PARAM_ACTION_PROLOGUE; - PARAM_CLASS_OPT(podtype, AActor) { podtype = PClass::FindClass("Pod"); } + PARAM_CLASS_OPT(podtype, AActor) { podtype = PClass::FindActor("Pod"); } AActor *mo; fixed_t x; diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index c6c22154d..ec1a052e1 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -82,7 +82,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StaffAttack) if (!weapon->DepleteAmmo (weapon->bAltFire)) return 0; } - if (puff == NULL) puff = PClass::FindClass(NAME_BulletPuff); // just to be sure + if (puff == NULL) + { + puff = PClass::FindActor(NAME_BulletPuff); // just to be sure + } angle = self->angle; angle += pr_sap.Random2() << 18; slope = P_AimLineAttack (self, angle, MELEERANGE, &linetarget); @@ -254,7 +257,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack) int randVal; fixed_t dist; player_t *player; - const PClass *pufftype; + PClassActor *pufftype; AActor *linetarget; if (NULL == (player = self->player)) @@ -278,14 +281,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack) damage = pr_gatk.HitDice (2); dist = 4*MELEERANGE; angle += pr_gatk.Random2() << 17; - pufftype = PClass::FindClass("GauntletPuff2"); + pufftype = PClass::FindActor("GauntletPuff2"); } else { damage = pr_gatk.HitDice (2); dist = MELEERANGE+1; angle += pr_gatk.Random2() << 18; - pufftype = PClass::FindClass("GauntletPuff1"); + pufftype = PClass::FindActor("GauntletPuff1"); } slope = P_AimLineAttack (self, angle, dist, &linetarget); P_LineAttack (self, angle, dist, slope, damage, NAME_Melee, pufftype); diff --git a/src/g_hexen/a_blastradius.cpp b/src/g_hexen/a_blastradius.cpp index 7a2a6028c..3ab01f4a5 100644 --- a/src/g_hexen/a_blastradius.cpp +++ b/src/g_hexen/a_blastradius.cpp @@ -100,7 +100,7 @@ DEFINE_ACTION_FUNCTION_PARAMS (AActor, A_Blast) PARAM_FIXED_OPT (strength) { strength = 255; } PARAM_FIXED_OPT (radius) { radius = 255; } PARAM_FIXED_OPT (speed) { speed = 20; } - PARAM_CLASS_OPT (blasteffect, AActor) { blasteffect = PClass::FindClass("BlastEffect"); } + PARAM_CLASS_OPT (blasteffect, AActor) { blasteffect = PClass::FindActor("BlastEffect"); } PARAM_SOUND_OPT (blastsound) { blastsound = "BlastRadius"; } AActor *mo; diff --git a/src/g_hexen/a_clericmace.cpp b/src/g_hexen/a_clericmace.cpp index cb9cc1b7b..39938183e 100644 --- a/src/g_hexen/a_clericmace.cpp +++ b/src/g_hexen/a_clericmace.cpp @@ -38,7 +38,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CMaceAttack) slope = P_AimLineAttack (player->mo, angle, 2*MELEERANGE, &linetarget); if (linetarget) { - P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff"), true); + P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, PClass::FindActor("HammerPuff"), true); AdjustPlayerAngle (player->mo, linetarget); // player->mo->angle = R_PointToAngle2(player->mo->x, // player->mo->y, linetarget->x, linetarget->y); @@ -48,7 +48,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CMaceAttack) slope = P_AimLineAttack (player->mo, angle, 2*MELEERANGE, &linetarget); if (linetarget) { - P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff"), true); + P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, PClass::FindActor("HammerPuff"), true); AdjustPlayerAngle (player->mo, linetarget); // player->mo->angle = R_PointToAngle2(player->mo->x, // player->mo->y, linetarget->x, linetarget->y); @@ -60,7 +60,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CMaceAttack) angle = player->mo->angle; slope = P_AimLineAttack (player->mo, angle, MELEERANGE, &linetarget); - P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff")); + P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, PClass::FindActor("HammerPuff")); macedone: return 0; } diff --git a/src/g_hexen/a_clericstaff.cpp b/src/g_hexen/a_clericstaff.cpp index 6c6481fb6..1b2bd74fa 100644 --- a/src/g_hexen/a_clericstaff.cpp +++ b/src/g_hexen/a_clericstaff.cpp @@ -72,7 +72,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) slope = P_AimLineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), &linetarget, 0, false, true); if (linetarget) { - P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, PClass::FindClass ("CStaffPuff")); + P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, PClass::FindActor("CStaffPuff")); pmo->angle = R_PointToAngle2 (pmo->x, pmo->y, linetarget->x, linetarget->y); if (((linetarget->player && (!linetarget->IsTeammate (pmo) || level.teamdamage != 0))|| linetarget->flags3&MF3_ISMONSTER) @@ -96,7 +96,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) slope = P_AimLineAttack (player->mo, angle, fixed_t(1.5*MELEERANGE), &linetarget, 0, false, true); if (linetarget) { - P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, PClass::FindClass ("CStaffPuff")); + P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, PClass::FindActor("CStaffPuff")); pmo->angle = R_PointToAngle2 (pmo->x, pmo->y, linetarget->x, linetarget->y); if ((linetarget->player && (!linetarget->IsTeammate (pmo) || level.teamdamage != 0)) || linetarget->flags3&MF3_ISMONSTER) diff --git a/src/g_hexen/a_fighteraxe.cpp b/src/g_hexen/a_fighteraxe.cpp index 8c5e8c540..37635c4ee 100644 --- a/src/g_hexen/a_fighteraxe.cpp +++ b/src/g_hexen/a_fighteraxe.cpp @@ -211,7 +211,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeAttack) int useMana; player_t *player; AWeapon *weapon; - const PClass *pufftype; + PClassActor *pufftype; AActor *linetarget; if (NULL == (player = self->player)) @@ -228,12 +228,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeAttack) { damage <<= 1; power = 6*FRACUNIT; - pufftype = PClass::FindClass ("AxePuffGlow"); + pufftype = PClass::FindActor ("AxePuffGlow"); useMana = 1; } else { - pufftype = PClass::FindClass ("AxePuff"); + pufftype = PClass::FindActor ("AxePuff"); useMana = 0; } for (i = 0; i < 16; i++) diff --git a/src/g_hexen/a_fighterhammer.cpp b/src/g_hexen/a_fighterhammer.cpp index 2116ec665..2eb226f2a 100644 --- a/src/g_hexen/a_fighterhammer.cpp +++ b/src/g_hexen/a_fighterhammer.cpp @@ -36,6 +36,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack) int i; player_t *player; AActor *linetarget; + PClassActor *hammertime; if (NULL == (player = self->player)) { @@ -45,13 +46,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack) damage = 60+(pr_hammeratk()&63); power = 10*FRACUNIT; + hammertime = PClass::FindActor("HammerPuff"); for (i = 0; i < 16; i++) { angle = pmo->angle + i*(ANG45/32); slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, &linetarget, 0, false, true); if (linetarget) { - P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff"), true); + P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true); AdjustPlayerAngle(pmo, linetarget); if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) { @@ -64,7 +66,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack) slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE, &linetarget, 0, false, true); if(linetarget) { - P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff"), true); + P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true); AdjustPlayerAngle(pmo, linetarget); if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) { @@ -77,7 +79,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack) // didn't find any targets in meleerange, so set to throw out a hammer angle = pmo->angle; slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, &linetarget, 0, false, true); - if (P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff"), true) != NULL) + if (P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true) != NULL) { pmo->special1 = false; } diff --git a/src/g_hexen/a_fighterplayer.cpp b/src/g_hexen/a_fighterplayer.cpp index afa15d702..db106b941 100644 --- a/src/g_hexen/a_fighterplayer.cpp +++ b/src/g_hexen/a_fighterplayer.cpp @@ -142,7 +142,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FPunchAttack) fixed_t power; int i; player_t *player; - const PClass *pufftype; + PClassActor *pufftype; AActor *linetarget; if (NULL == (player = self->player)) @@ -153,7 +153,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FPunchAttack) damage = 40+(pr_fpatk()&15); power = 2*FRACUNIT; - pufftype = PClass::FindClass ("PunchPuff"); + pufftype = PClass::FindActor("PunchPuff"); for (i = 0; i < 16; i++) { angle = pmo->angle + i*(ANG45/16); @@ -165,7 +165,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FPunchAttack) { damage <<= 1; power = 6*FRACUNIT; - pufftype = PClass::FindClass ("HammerPuff"); + pufftype = PClass::FindActor("HammerPuff"); } P_LineAttack (pmo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, pufftype, true); if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) @@ -184,7 +184,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FPunchAttack) { damage <<= 1; power = 6*FRACUNIT; - pufftype = PClass::FindClass ("HammerPuff"); + pufftype = PClass::FindActor("HammerPuff"); } P_LineAttack (pmo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, pufftype, true); if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) diff --git a/src/g_hexen/a_magelightning.cpp b/src/g_hexen/a_magelightning.cpp index e124eb537..5d9880a40 100644 --- a/src/g_hexen/a_magelightning.cpp +++ b/src/g_hexen/a_magelightning.cpp @@ -269,8 +269,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightningZap) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MLightningAttack) { PARAM_ACTION_PROLOGUE; - PARAM_CLASS_OPT(floor, AActor) { floor = PClass::FindClass("LightningFloor"); } - PARAM_CLASS_OPT(ceiling, AActor) { ceiling = PClass::FindClass("LightningCeiling"); } + PARAM_CLASS_OPT(floor, AActor) { floor = PClass::FindActor("LightningFloor"); } + PARAM_CLASS_OPT(ceiling, AActor) { ceiling = PClass::FindActor("LightningCeiling"); } AActor *fmo, *cmo; diff --git a/src/g_hexen/hexen_sbar.cpp b/src/g_hexen/hexen_sbar.cpp index 787b8f8d9..caf62e59e 100644 --- a/src/g_hexen/hexen_sbar.cpp +++ b/src/g_hexen/hexen_sbar.cpp @@ -29,7 +29,7 @@ public: void Unload (); bool CheckModified (); - void SetVial (FTexture *pic, AActor *actor, const PClass *manaType); + void SetVial (FTexture *pic, AActor *actor, PClassActor *manaType); protected: BYTE Pixels[5*24]; @@ -93,7 +93,7 @@ const BYTE *FManaBar::GetPixels () return Pixels; } -void FManaBar::SetVial (FTexture *pic, AActor *actor, const PClass *manaType) +void FManaBar::SetVial (FTexture *pic, AActor *actor, PClassActor *manaType) { int level, max; AInventory *ammo; @@ -457,8 +457,8 @@ private: // If the weapon uses some ammo that is not mana, do not draw // the mana bars; draw the specific used ammo instead. - const PClass *mana1 = PClass::FindClass(NAME_Mana1); - const PClass *mana2 = PClass::FindClass(NAME_Mana2); + PClassActor *mana1 = PClass::FindActor(NAME_Mana1); + PClassActor *mana2 = PClass::FindActor(NAME_Mana2); drawbar = !((ammo1 != NULL && ammo1->GetClass() != mana1 && ammo1->GetClass() != mana2) || (ammo2 != NULL && ammo2->GetClass() != mana1 && ammo2->GetClass() != mana2)); @@ -564,7 +564,7 @@ private: // //--------------------------------------------------------------------------- - void DrawManaBars (AAmmo *ammo1, AAmmo *ammo2, const PClass *manatype1, const PClass *manatype2) + void DrawManaBars (AAmmo *ammo1, AAmmo *ammo2, PClassActor *manatype1, PClassActor *manatype2) { AAmmo *mana1 = NULL, *mana2 = NULL; int usemana1 = false, usemana2 = false; @@ -1004,8 +1004,8 @@ private: // If the weapon uses some ammo that is not mana, do not draw // the mana blocks; draw the specific used ammo instead. - const PClass *mana1 = PClass::FindClass(NAME_Mana1); - const PClass *mana2 = PClass::FindClass(NAME_Mana2); + PClassActor *mana1 = PClass::FindActor(NAME_Mana1); + PClassActor *mana2 = PClass::FindActor(NAME_Mana2); drawmana = !((ammo1 != NULL && ammo1->GetClass() != mana1 && ammo1->GetClass() != mana2) || (ammo2 != NULL && ammo2->GetClass() != mana1 && ammo2->GetClass() != mana2)); diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index f85b08960..cfdaf75c1 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -351,12 +351,12 @@ level_info_t *level_info_t::CheckLevelRedirect () { if (RedirectType != NAME_None) { - const PClass *type = PClass::FindClass(RedirectType); + PClassActor *type = PClass::FindActor(RedirectType); if (type != NULL) { for (int i = 0; i < MAXPLAYERS; ++i) { - if (playeringame[i] && players[i].mo->FindInventory (type)) + if (playeringame[i] && players[i].mo->FindInventory(type)) { // check for actual presence of the map. if (P_CheckMapData(RedirectMap)) diff --git a/src/g_raven/a_artitele.cpp b/src/g_raven/a_artitele.cpp index 9828f9581..aa07921d3 100644 --- a/src/g_raven/a_artitele.cpp +++ b/src/g_raven/a_artitele.cpp @@ -66,7 +66,7 @@ bool AArtiTeleport::Use (bool pickup) bool P_AutoUseChaosDevice (player_t *player) { - AInventory *arti = player->mo->FindInventory(PClass::FindClass("ArtiTeleport")); + AInventory *arti = player->mo->FindInventory(PClass::FindActor("ArtiTeleport")); if (arti != NULL) { diff --git a/src/g_raven/a_minotaur.cpp b/src/g_raven/a_minotaur.cpp index 078a065f4..cb51a32d0 100644 --- a/src/g_raven/a_minotaur.cpp +++ b/src/g_raven/a_minotaur.cpp @@ -104,7 +104,7 @@ void AMinotaurFriend::Die (AActor *source, AActor *inflictor) if (mo == NULL) { - AInventory *power = tracer->FindInventory (PClass::FindClass("PowerMinotaur")); + AInventory *power = tracer->FindInventory(PClass::FindActor("PowerMinotaur")); if (power != NULL) { power->Destroy (); diff --git a/src/g_shared/a_armor.cpp b/src/g_shared/a_armor.cpp index 9e43ccfb6..4230efe7d 100644 --- a/src/g_shared/a_armor.cpp +++ b/src/g_shared/a_armor.cpp @@ -160,7 +160,7 @@ void ABasicArmor::AbsorbDamage (int damage, FName damageType, int &newdamage) // The differences include not checking for the NAME_None key (doesn't seem appropriate here), // not using a default value, and of course the way the damage factor info is obtained. const fixed_t *pdf = NULL; - DmgFactors *df = PClass::FindClass(ArmorType)->ActorInfo->DamageFactors; + DmgFactors *df = PClass::FindActor(ArmorType)->DamageFactors; if (df != NULL && df->CountUsed() != 0) { pdf = df->CheckKey(damageType); diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index fa2c1e59f..ec49b683d 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -1459,8 +1459,8 @@ void APowerDamage::ModifyDamage(int damage, FName damageType, int &newdamage, bo static const fixed_t def = 4*FRACUNIT; if (!passive && damage > 0) { - const fixed_t * pdf = NULL; - DmgFactors * df = GetClass()->ActorInfo->DamageFactors; + const fixed_t *pdf = NULL; + DmgFactors *df = GetClass()->DamageFactors; if (df != NULL && df->CountUsed() != 0) { pdf = df->CheckKey(damageType); @@ -1538,7 +1538,7 @@ void APowerProtection::ModifyDamage(int damage, FName damageType, int &newdamage if (passive && damage > 0) { const fixed_t *pdf = NULL; - DmgFactors *df = GetClass()->ActorInfo->DamageFactors; + DmgFactors *df = GetClass()->DamageFactors; if (df != NULL && df->CountUsed() != 0) { pdf = df->CheckKey(damageType); diff --git a/src/g_shared/a_artifacts.h b/src/g_shared/a_artifacts.h index 93352a719..6cd45b035 100644 --- a/src/g_shared/a_artifacts.h +++ b/src/g_shared/a_artifacts.h @@ -40,7 +40,7 @@ public: virtual bool Use (bool pickup); virtual void Serialize (FArchive &arc); - const PClass *PowerupType; + PClassActor *PowerupType; int EffectTics; // Non-0 to override the powerup's default tics PalEntry BlendColor; // Non-0 to override the powerup's default blend FNameNoInit Mode; // Meaning depends on powerup - used for Invulnerability and Invisibility diff --git a/src/g_shared/a_bridge.cpp b/src/g_shared/a_bridge.cpp index 99a7c1a70..583656dd1 100644 --- a/src/g_shared/a_bridge.cpp +++ b/src/g_shared/a_bridge.cpp @@ -112,7 +112,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BridgeInit) AActor *ball; fixed_t cx, cy, cz; - if (balltype == NULL) balltype = PClass::FindClass("BridgeBall"); + if (balltype == NULL) + { + balltype = PClass::FindActor("BridgeBall"); + } cx = self->x; cy = self->y; diff --git a/src/g_shared/a_keys.cpp b/src/g_shared/a_keys.cpp index 5ec5479e5..c0e13e414 100644 --- a/src/g_shared/a_keys.cpp +++ b/src/g_shared/a_keys.cpp @@ -14,10 +14,10 @@ struct OneKey { - const PClass *key; + PClassActor *key; int count; - bool check(AActor * owner) + bool check(AActor *owner) { return !!owner->FindInventory(key); } @@ -99,7 +99,7 @@ static const char * keywords_lock[]={ // //=========================================================================== -static void AddOneKey(Keygroup *keygroup, const PClass *mi, FScanner &sc) +static void AddOneKey(Keygroup *keygroup, PClassActor *mi, FScanner &sc) { if (mi) { @@ -136,17 +136,17 @@ static void AddOneKey(Keygroup *keygroup, const PClass *mi, FScanner &sc) // //=========================================================================== -static Keygroup * ParseKeygroup(FScanner &sc) +static Keygroup *ParseKeygroup(FScanner &sc) { - Keygroup * keygroup; - const PClass * mi; + Keygroup *keygroup; + PClassActor *mi; sc.MustGetStringName("{"); keygroup = new Keygroup; while (!sc.CheckString("}")) { sc.MustGetString(); - mi = PClass::FindClass(sc.String); + mi = PClass::FindActor(sc.String); AddOneKey(keygroup, mi, sc); } if (keygroup->anykeylist.Size() == 0) @@ -185,9 +185,9 @@ static void ParseLock(FScanner &sc) int i,r,g,b; int keynum; Lock sink; - Lock * lock=&sink; - Keygroup * keygroup; - const PClass * mi; + Lock *lock = &sink; + Keygroup *keygroup; + PClassActor *mi; sc.MustGetNumber(); keynum = sc.Number; @@ -272,7 +272,7 @@ static void ParseLock(FScanner &sc) break; default: - mi = PClass::FindClass(sc.String); + mi = PClass::FindActor(sc.String); if (mi) { keygroup = new Keygroup; diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index a807ad70b..7cbfbc5ad 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -330,8 +330,8 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, } if (correctweapon) { // Better "lose morphed weapon" semantics - const PClass *morphweapon = PClass::FindClass (pmo->MorphWeapon); - if (morphweapon != NULL && morphweapon->IsDescendantOf (RUNTIME_CLASS(AWeapon))) + PClassActor *morphweapon = PClass::FindActor(pmo->MorphWeapon); + if (morphweapon != NULL && morphweapon->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { AWeapon *OriginalMorphWeapon = static_cast<AWeapon *>(mo->FindInventory (morphweapon)); if ((OriginalMorphWeapon != NULL) && (OriginalMorphWeapon->GivenAsMorphWeapon)) diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 640570016..eb7a25425 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -51,15 +51,15 @@ void AAmmo::Serialize (FArchive &arc) // //=========================================================================== -const PClass *AAmmo::GetParentAmmo () const +PClassActor *AAmmo::GetParentAmmo () const { - const PClass *type = GetClass (); + PClass *type = GetClass(); while (type->ParentClass != RUNTIME_CLASS(AAmmo) && type->ParentClass != NULL) { type = type->ParentClass; } - return type; + return static_cast<PClassActor *>(type); } //=========================================================================== @@ -130,8 +130,7 @@ AInventory *AAmmo::CreateCopy (AActor *other) if (GetClass()->ParentClass != RUNTIME_CLASS(AAmmo) && GetClass() != RUNTIME_CLASS(AAmmo)) { - const PClass *type = GetParentAmmo(); - assert (type->ActorInfo != NULL); + PClassActor *type = GetParentAmmo(); if (!GoAway ()) { Destroy (); @@ -1584,11 +1583,12 @@ AInventory *ABackpackItem::CreateCopy (AActor *other) // he doesn't have it already, and double its maximum capacity. for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) { - const PClass *type = PClass::m_Types[i]; + PClass *type = PClass::m_Types[i]; if (type->ParentClass == RUNTIME_CLASS(AAmmo)) { - AAmmo *ammo = static_cast<AAmmo *>(other->FindInventory (type)); + PClassActor *atype = static_cast<PClassActor *>(type); + AAmmo *ammo = static_cast<AAmmo *>(other->FindInventory(atype)); int amount = static_cast<AAmmo *>(GetDefaultByType(type))->BackpackAmount; // extra ammo in baby mode and nightmare mode if (!(ItemFlags&IF_IGNORESKILL)) diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index b402fcf59..0e531066f 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -19,13 +19,13 @@ public: FWeaponSlot &operator= (const FWeaponSlot &other) { Weapons = other.Weapons; return *this; } void Clear() { Weapons.Clear(); } bool AddWeapon (const char *type); - bool AddWeapon (const PClass *type); + bool AddWeapon (PClassActor *type); void AddWeaponList (const char *list, bool clear); AWeapon *PickWeapon (player_t *player); int Size () const { return (int)Weapons.Size(); } - int LocateWeapon (const PClass *type); + int LocateWeapon (PClassActor *type); - inline const PClass *GetWeapon (int index) const + inline PClassActor *GetWeapon (int index) const { if ((unsigned)index < Weapons.Size()) { @@ -42,7 +42,7 @@ public: private: struct WeaponInfo { - const PClass *Type; + PClassActor *Type; fixed_t Position; }; void SetInitialPositions(); @@ -68,25 +68,25 @@ struct FWeaponSlots AWeapon *PickPrevWeapon (player_t *player); void Clear (); - bool LocateWeapon (const PClass *type, int *const slot, int *const index); - ESlotDef AddDefaultWeapon (int slot, const PClass *type); + bool LocateWeapon (PClassActor *type, int *const slot, int *const index); + ESlotDef AddDefaultWeapon (int slot, PClassActor *type); void AddExtraWeapons(); void SetFromGameInfo(); - void SetFromPlayer(const PClass *type); - void StandardSetup(const PClass *type); - void LocalSetup(const PClass *type); + void SetFromPlayer(PClassActor *type); + void StandardSetup(PClassActor *type); + void LocalSetup(PClassActor *type); void SendDifferences(const FWeaponSlots &other); int RestoreSlots (FConfigFile *config, const char *section); void PrintSettings(); - void AddSlot(int slot, const PClass *type, bool feedback); - void AddSlotDefault(int slot, const PClass *type, bool feedback); + void AddSlot(int slot, PClassActor *type, bool feedback); + void AddSlotDefault(int slot, PClassActor *type, bool feedback); }; void P_PlaybackKeyConfWeapons(FWeaponSlots *slots); -void Net_WriteWeapon(const PClass *type); -const PClass *Net_ReadWeapon(BYTE **stream); +void Net_WriteWeapon(PClassActor *type); +PClassActor *Net_ReadWeapon(BYTE **stream); void P_SetupWeapons_ntohton(); void P_WriteDemoWeaponsChunk(BYTE **demo); @@ -227,7 +227,7 @@ public: void Serialize (FArchive &arc); AInventory *CreateCopy (AActor *other); bool HandlePickup (AInventory *item); - const PClass *GetParentAmmo () const; + PClassActor *GetParentAmmo () const; AInventory *CreateTossable (); int BackpackAmount, BackpackMaxAmount; @@ -247,16 +247,16 @@ class AWeapon : public AInventory HAS_OBJECT_POINTERS public: DWORD WeaponFlags; - const PClass *AmmoType1, *AmmoType2; // Types of ammo used by this weapon + PClassActor *AmmoType1, *AmmoType2; // Types of ammo used by this weapon int AmmoGive1, AmmoGive2; // Amount of each ammo to get when picking up weapon int MinAmmo1, MinAmmo2; // Minimum ammo needed to switch to this weapon int AmmoUse1, AmmoUse2; // How much ammo to use with each shot int Kickback; fixed_t YAdjust; // For viewing the weapon fullscreen FSoundIDNoInit UpSound, ReadySound; // Sounds when coming up and idle - const PClass *SisterWeaponType; // Another weapon to pick up with this one - const PClass *ProjectileType; // Projectile used by primary attack - const PClass *AltProjectileType; // Projectile used by alternate attack + PClassActor *SisterWeaponType; // Another weapon to pick up with this one + PClassActor *ProjectileType; // Projectile used by primary attack + PClassActor *AltProjectileType; // Projectile used by alternate attack int SelectionOrder; // Lower-numbered weapons get picked first fixed_t MoveCombatDist; // Used by bots, but do they *really* need it? int ReloadCounter; // For A_CheckForReload @@ -300,9 +300,9 @@ public: bool DepleteAmmo (bool altFire, bool checkEnough=true); protected: - AAmmo *AddAmmo (AActor *other, const PClass *ammotype, int amount); + AAmmo *AddAmmo (AActor *other, PClassActor *ammotype, int amount); bool AddExistingAmmo (AAmmo *ammo, int amount); - AWeapon *AddWeapon (const PClass *weapon); + AWeapon *AddWeapon (PClassActor *weapon); }; enum diff --git a/src/g_shared/a_randomspawner.cpp b/src/g_shared/a_randomspawner.cpp index 0df69228a..026788e78 100644 --- a/src/g_shared/a_randomspawner.cpp +++ b/src/g_shared/a_randomspawner.cpp @@ -67,11 +67,11 @@ class ARandomSpawner : public AActor else if (pr_randomspawn() <= di->probability) // prob 255 = always spawn, prob 0 = never spawn. { // Handle replacement here so as to get the proper speed and flags for missiles - const PClass *cls; - cls = PClass::FindClass(di->Name); + PClassActor *cls; + cls = PClass::FindActor(di->Name); if (cls != NULL) { - const PClass *rep = cls->ActorInfo->GetReplacement()->Class; + PClassActor *rep = cls->GetReplacement(); if (rep != NULL) { cls = rep; @@ -160,7 +160,7 @@ class ARandomSpawner : public AActor if ((newmobj->flags4 & MF4_BOSSDEATH) || (newmobj->flags2 & MF2_BOSS)) boss = true; // If a replaced actor has either of those same flags, it's also a boss. - AActor * rep = GetDefaultByType(GetClass()->ActorInfo->GetReplacee()->Class); + AActor *rep = GetDefaultByType(GetClass()->GetReplacee()); if (rep && ((rep->flags4 & MF4_BOSSDEATH) || (rep->flags2 & MF2_BOSS))) boss = true; } diff --git a/src/g_shared/a_weaponpiece.h b/src/g_shared/a_weaponpiece.h index b59c77f6e..3d609d8c5 100644 --- a/src/g_shared/a_weaponpiece.h +++ b/src/g_shared/a_weaponpiece.h @@ -13,7 +13,7 @@ public: virtual void PlayPickupSound (AActor *toucher); int PieceValue; - const PClass * WeaponClass; + PClassActor *WeaponClass; TObjPtr<AWeapon> FullWeapon; }; diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index d2387fba0..f1f488557 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -30,8 +30,8 @@ FString WeaponSection; TArray<FString> KeyConfWeapons; FWeaponSlots *PlayingKeyConf; -TArray<const PClass *> Weapons_ntoh; -TMap<const PClass *, int> Weapons_hton; +TArray<PClassActor *> Weapons_ntoh; +TMap<PClassActor *, int> Weapons_hton; static int STACK_ARGS ntoh_cmp(const void *a, const void *b); @@ -284,7 +284,7 @@ void AWeapon::AttachToOwner (AActor *other) // //=========================================================================== -AAmmo *AWeapon::AddAmmo (AActor *other, const PClass *ammotype, int amount) +AAmmo *AWeapon::AddAmmo (AActor *other, PClassActor *ammotype, int amount) { AAmmo *ammo; @@ -357,7 +357,7 @@ bool AWeapon::AddExistingAmmo (AAmmo *ammo, int amount) // //=========================================================================== -AWeapon *AWeapon::AddWeapon (const PClass *weapontype) +AWeapon *AWeapon::AddWeapon (PClassActor *weapontype) { AWeapon *weap; @@ -625,8 +625,8 @@ bool AWeaponGiver::TryPickup(AActor *&toucher) if (di != NULL) { - const PClass *ti = PClass::FindClass(di->Name); - if (ti->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + PClassActor *ti = PClass::FindActor(di->Name); + if (ti != NULL && ti->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { if (master == NULL) { @@ -662,10 +662,10 @@ bool AWeaponGiver::TryPickup(AActor *&toucher) bool FWeaponSlot::AddWeapon(const char *type) { - return AddWeapon (PClass::FindClass (type)); + return AddWeapon (PClass::FindActor (type)); } -bool FWeaponSlot::AddWeapon(const PClass *type) +bool FWeaponSlot::AddWeapon(PClassActor *type) { unsigned int i; @@ -726,7 +726,7 @@ void FWeaponSlot :: AddWeaponList(const char *list, bool clear) // //=========================================================================== -int FWeaponSlot::LocateWeapon(const PClass *type) +int FWeaponSlot::LocateWeapon(PClassActor *type) { unsigned int i; @@ -842,7 +842,7 @@ void FWeaponSlot::Sort() for (i = 1; i < (int)Weapons.Size(); ++i) { fixed_t pos = Weapons[i].Position; - const PClass *type = Weapons[i].Type; + PClassActor *type = Weapons[i].Type; for (j = i - 1; j >= 0 && Weapons[j].Position > pos; --j) { Weapons[j + 1] = Weapons[j]; @@ -891,7 +891,7 @@ void FWeaponSlots::Clear() // //=========================================================================== -ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, const PClass *type) +ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, PClassActor *type) { int currSlot, index; @@ -916,7 +916,7 @@ ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, const PClass *type) // //=========================================================================== -bool FWeaponSlots::LocateWeapon (const PClass *type, int *const slot, int *const index) +bool FWeaponSlots::LocateWeapon (PClassActor *type, int *const slot, int *const index) { int i, j; @@ -1014,7 +1014,7 @@ AWeapon *FWeaponSlots::PickNextWeapon(player_t *player) slot = 0; } } - const PClass *type = Slots[slot].GetWeapon(index); + PClassActor *type = Slots[slot].GetWeapon(index); AWeapon *weap = static_cast<AWeapon *>(player->mo->FindInventory(type)); if (weap != NULL && weap->CheckAmmo(AWeapon::EitherFire, false)) { @@ -1069,7 +1069,7 @@ AWeapon *FWeaponSlots::PickPrevWeapon (player_t *player) } index = Slots[slot].Size() - 1; } - const PClass *type = Slots[slot].GetWeapon(index); + PClassActor *type = Slots[slot].GetWeapon(index); AWeapon *weap = static_cast<AWeapon *>(player->mo->FindInventory(type)); if (weap != NULL && weap->CheckAmmo(AWeapon::EitherFire, false)) { @@ -1105,18 +1105,21 @@ void FWeaponSlots::AddExtraWeapons() { PClass *cls = PClass::m_Types[i]; - if (cls->ActorInfo != NULL && - (cls->ActorInfo->GameFilter == GAME_Any || (cls->ActorInfo->GameFilter & gameinfo.gametype)) && - cls->ActorInfo->Replacement == NULL && // Replaced weapons don't get slotted. - cls->IsDescendantOf(RUNTIME_CLASS(AWeapon)) && - !LocateWeapon(cls, NULL, NULL) // Don't duplicate it if it's already present. + if (!cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + { + continue; + } + PClassActor *acls = static_cast<PClassActor *>(cls); + if ((acls->GameFilter == GAME_Any || (acls->GameFilter & gameinfo.gametype)) && + acls->Replacement == NULL && // Replaced weapons don't get slotted. + !LocateWeapon(acls, NULL, NULL) // Don't duplicate it if it's already present. ) { - int slot = cls->Meta.GetMetaInt(AWMETA_SlotNumber, -1); + int slot = acls->Meta.GetMetaInt(AWMETA_SlotNumber, -1); if ((unsigned)slot < NUM_WEAPON_SLOTS) { - fixed_t position = cls->Meta.GetMetaFixed(AWMETA_SlotPriority, INT_MAX); - FWeaponSlot::WeaponInfo info = { cls, position }; + fixed_t position = acls->Meta.GetMetaFixed(AWMETA_SlotPriority, INT_MAX); + FWeaponSlot::WeaponInfo info = { acls, position }; Slots[slot].Weapons.Push(info); } } @@ -1153,7 +1156,7 @@ void FWeaponSlots::SetFromGameInfo() { for (unsigned j = 0; j < gameinfo.DefaultWeaponSlots[i].Size(); i++) { - const PClass *cls = PClass::FindClass(gameinfo.DefaultWeaponSlots[i][j]); + PClassActor *cls = PClass::FindActor(gameinfo.DefaultWeaponSlots[i][j]); if (cls == NULL) { Printf("Unknown weapon class '%s' found in default weapon slot assignments\n", @@ -1178,7 +1181,7 @@ void FWeaponSlots::SetFromGameInfo() // //=========================================================================== -void FWeaponSlots::StandardSetup(const PClass *type) +void FWeaponSlots::StandardSetup(PClassActor *type) { SetFromPlayer(type); AddExtraWeapons(); @@ -1198,7 +1201,7 @@ void FWeaponSlots::StandardSetup(const PClass *type) // //=========================================================================== -void FWeaponSlots::LocalSetup(const PClass *type) +void FWeaponSlots::LocalSetup(PClassActor *type) { P_PlaybackKeyConfWeapons(this); if (WeaponSection.IsNotEmpty()) @@ -1263,7 +1266,7 @@ void FWeaponSlots::SendDifferences(const FWeaponSlots &other) // //=========================================================================== -void FWeaponSlots::SetFromPlayer(const PClass *type) +void FWeaponSlots::SetFromPlayer(PClassActor *type) { Clear(); for (int i = 0; i < NUM_WEAPON_SLOTS; ++i) @@ -1382,7 +1385,7 @@ CCMD (setslot) Net_WriteByte(argv.argc()-2); for (int i = 2; i < argv.argc(); i++) { - Net_WriteWeapon(PClass::FindClass(argv[i])); + Net_WriteWeapon(PClass::FindActor(argv[i])); } } } @@ -1393,7 +1396,7 @@ CCMD (setslot) // //=========================================================================== -void FWeaponSlots::AddSlot(int slot, const PClass *type, bool feedback) +void FWeaponSlots::AddSlot(int slot, PClassActor *type, bool feedback) { if (type != NULL && !Slots[slot].AddWeapon(type) && feedback) { @@ -1417,13 +1420,13 @@ CCMD (addslot) } else if (PlayingKeyConf != NULL) { - PlayingKeyConf->AddSlot(int(slot), PClass::FindClass(argv[2]), false); + PlayingKeyConf->AddSlot(int(slot), PClass::FindActor(argv[2]), false); } else { Net_WriteByte(DEM_ADDSLOT); Net_WriteByte(slot); - Net_WriteWeapon(PClass::FindClass(argv[2])); + Net_WriteWeapon(PClass::FindActor(argv[2])); } } @@ -1446,7 +1449,7 @@ CCMD (weaponsection) // CCMD addslotdefault // //=========================================================================== -void FWeaponSlots::AddSlotDefault(int slot, const PClass *type, bool feedback) +void FWeaponSlots::AddSlotDefault(int slot, PClassActor *type, bool feedback) { if (type != NULL && type->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { @@ -1471,7 +1474,7 @@ void FWeaponSlots::AddSlotDefault(int slot, const PClass *type, bool feedback) CCMD (addslotdefault) { - const PClass *type; + PClassActor *type; unsigned int slot; if (argv.argc() != 3 || (slot = atoi (argv[1])) >= NUM_WEAPON_SLOTS) @@ -1480,7 +1483,7 @@ CCMD (addslotdefault) return; } - type = PClass::FindClass (argv[2]); + type = PClass::FindActor(argv[2]); if (type == NULL || !type->IsDescendantOf (RUNTIME_CLASS(AWeapon))) { Printf ("%s is not a weapon\n", argv[2]); @@ -1493,13 +1496,13 @@ CCMD (addslotdefault) } else if (PlayingKeyConf != NULL) { - PlayingKeyConf->AddSlotDefault(int(slot), PClass::FindClass(argv[2]), false); + PlayingKeyConf->AddSlotDefault(int(slot), PClass::FindActor(argv[2]), false); } else { Net_WriteByte(DEM_ADDSLOTDEFAULT); Net_WriteByte(slot); - Net_WriteWeapon(PClass::FindClass(argv[2])); + Net_WriteWeapon(PClass::FindActor(argv[2])); } } @@ -1536,7 +1539,7 @@ void P_PlaybackKeyConfWeapons(FWeaponSlots *slots) void P_SetupWeapons_ntohton() { unsigned int i; - const PClass *cls; + PClassActor *cls; Weapons_ntoh.Clear(); Weapons_hton.Clear(); @@ -1547,9 +1550,9 @@ void P_SetupWeapons_ntohton() { PClass *cls = PClass::m_Types[i]; - if (cls->ActorInfo != NULL && cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { - Weapons_ntoh.Push(cls); + Weapons_ntoh.Push(static_cast<PClassActor *>(cls)); } } qsort(&Weapons_ntoh[1], Weapons_ntoh.Size() - 1, sizeof(Weapons_ntoh[0]), ntoh_cmp); @@ -1575,10 +1578,10 @@ void P_SetupWeapons_ntohton() static int STACK_ARGS ntoh_cmp(const void *a, const void *b) { - const PClass *c1 = *(const PClass **)a; - const PClass *c2 = *(const PClass **)b; - int g1 = c1->ActorInfo->GameFilter == GAME_Any ? 1 : (c1->ActorInfo->GameFilter & gameinfo.gametype) ? 0 : 2; - int g2 = c2->ActorInfo->GameFilter == GAME_Any ? 1 : (c2->ActorInfo->GameFilter & gameinfo.gametype) ? 0 : 2; + PClassActor *c1 = *(PClassActor **)a; + PClassActor *c2 = *(PClassActor **)b; + int g1 = c1->GameFilter == GAME_Any ? 1 : (c1->GameFilter & gameinfo.gametype) ? 0 : 2; + int g2 = c2->GameFilter == GAME_Any ? 1 : (c2->GameFilter & gameinfo.gametype) ? 0 : 2; if (g1 != g2) { return g1 - g2; @@ -1616,7 +1619,7 @@ void P_WriteDemoWeaponsChunk(BYTE **demo) void P_ReadDemoWeaponsChunk(BYTE **demo) { int count, i; - const PClass *type; + PClassActor *type; const char *s; count = ReadWord(demo); @@ -1629,7 +1632,7 @@ void P_ReadDemoWeaponsChunk(BYTE **demo) for (i = 1; i < count; ++i) { s = ReadStringConst(demo); - type = PClass::FindClass(s); + type = PClass::FindActor(s); // If a demo was recorded with a weapon that is no longer present, // should we report it? Weapons_ntoh[i] = type; @@ -1646,7 +1649,7 @@ void P_ReadDemoWeaponsChunk(BYTE **demo) // //=========================================================================== -void Net_WriteWeapon(const PClass *type) +void Net_WriteWeapon(PClassActor *type) { int index, *index_p; @@ -1678,7 +1681,7 @@ void Net_WriteWeapon(const PClass *type) // //=========================================================================== -const PClass *Net_ReadWeapon(BYTE **stream) +PClassActor *Net_ReadWeapon(BYTE **stream) { int index; diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index ebc6dad46..cbde68ff9 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -106,7 +106,7 @@ class CommandDrawImage : public SBarInfoCommand { type = INVENTORYICON; const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of Inventory + if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item)) //must be a kind of Inventory { sc.ScriptError("'%s' is not a type of inventory item.", sc.String); } @@ -322,7 +322,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage { inventoryItem[0] = sc.String; const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of Inventory + if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item)) //must be a kind of Inventory { sc.ScriptError("'%s' is not a type of inventory item.", sc.String); } @@ -347,7 +347,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage sc.MustGetToken(TK_Identifier); inventoryItem[1] = sc.String; const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of Inventory + if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item)) //must be a kind of Inventory { sc.ScriptError("'%s' is not a type of inventory item.", sc.String); } @@ -378,7 +378,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage drawAlt = 1; //draw off state until we know we have something. for (int i = 0; i < statusBar->CPlayer->weapons.Slots[conditionalValue[0]].Size(); i++) { - const PClass *weap = statusBar->CPlayer->weapons.Slots[conditionalValue[0]].GetWeapon(i); + PClassActor *weap = statusBar->CPlayer->weapons.Slots[conditionalValue[0]].GetWeapon(i); if(weap == NULL) { continue; @@ -455,12 +455,12 @@ class CommandDrawSwitchableImage : public CommandDrawImage } else //check the inventory items and draw selected sprite { - AInventory* item = statusBar->CPlayer->mo->FindInventory(PClass::FindClass(inventoryItem[0])); + AInventory* item = statusBar->CPlayer->mo->FindInventory(PClass::FindActor(inventoryItem[0])); if(item == NULL || !EvaluateOperation(conditionalOperator[0], conditionalValue[0], item->Amount)) drawAlt = 1; if(conditionAnd) { - item = statusBar->CPlayer->mo->FindInventory(PClass::FindClass(inventoryItem[1])); + item = statusBar->CPlayer->mo->FindInventory(PClass::FindActor(inventoryItem[1])); bool secondCondition = item != NULL && EvaluateOperation(conditionalOperator[1], conditionalValue[1], item->Amount); if((item != NULL && secondCondition) && drawAlt == 0) //both { @@ -605,7 +605,7 @@ class CommandDrawNumber : public CommandDrawString { value = AMMO; sc.MustGetToken(TK_Identifier); - inventoryItem = PClass::FindClass(sc.String); + inventoryItem = PClass::FindActor(sc.String); if(inventoryItem == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo { sc.ScriptError("'%s' is not a type of ammo.", sc.String); @@ -615,7 +615,7 @@ class CommandDrawNumber : public CommandDrawString { value = AMMOCAPACITY; sc.MustGetToken(TK_Identifier); - inventoryItem = PClass::FindClass(sc.String); + inventoryItem = PClass::FindActor(sc.String); if(inventoryItem == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo { sc.ScriptError("'%s' is not a type of ammo.", sc.String); @@ -659,8 +659,8 @@ class CommandDrawNumber : public CommandDrawString { value = POWERUPTIME; sc.MustGetToken(TK_Identifier); - inventoryItem = PClass::FindClass(sc.String); - if(inventoryItem == NULL || !PClass::FindClass("PowerupGiver")->IsAncestorOf(inventoryItem)) + inventoryItem = PClass::FindActor(sc.String); + if(inventoryItem == NULL || !RUNTIME_CLASS(APowerupGiver)->IsAncestorOf(inventoryItem)) { sc.ScriptError("'%s' is not a type of PowerupGiver.", sc.String); } @@ -668,8 +668,8 @@ class CommandDrawNumber : public CommandDrawString else { value = INVENTORY; - inventoryItem = PClass::FindClass(sc.String); - if(inventoryItem == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(inventoryItem)) //must be a kind of ammo + inventoryItem = PClass::FindActor(sc.String); + if(inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(inventoryItem)) //must be a kind of ammo { sc.ScriptError("'%s' is not a type of inventory item.", sc.String); } @@ -831,7 +831,7 @@ class CommandDrawNumber : public CommandDrawString case POWERUPTIME: { //Get the PowerupType and check to see if the player has any in inventory. - const PClass* powerupType = ((APowerupGiver*) GetDefaultByType(inventoryItem))->PowerupType; + PClassActor* powerupType = ((APowerupGiver*) GetDefaultByType(inventoryItem))->PowerupType; APowerup* powerup = (APowerup*) statusBar->CPlayer->mo->FindInventory(powerupType); if(powerup != NULL) num = powerup->EffectTics / TICRATE + 1; @@ -949,7 +949,7 @@ class CommandDrawNumber : public CommandDrawString EColorRange normalTranslation; ValueType value; int valueArgument; - const PClass *inventoryItem; + PClassActor *inventoryItem; SBarInfoCoordinate startX; @@ -1811,8 +1811,8 @@ class CommandDrawBar : public SBarInfoCommand type = HEALTH; if(sc.CheckToken(TK_Identifier)) //comparing reference { - inventoryItem = PClass::FindClass(sc.String); - if(inventoryItem == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(inventoryItem)) //must be a kind of inventory + inventoryItem = PClass::FindActor(sc.String); + if(inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(inventoryItem)) //must be a kind of inventory sc.ScriptError("'%s' is not a type of inventory item.", sc.String); } } @@ -1821,8 +1821,8 @@ class CommandDrawBar : public SBarInfoCommand type = ARMOR; if(sc.CheckToken(TK_Identifier)) { - inventoryItem = PClass::FindClass(sc.String); - if(inventoryItem == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(inventoryItem)) //must be a kind of inventory + inventoryItem = PClass::FindActor(sc.String); + if(inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(inventoryItem)) //must be a kind of inventory sc.ScriptError("'%s' is not a type of inventory item.", sc.String); } } @@ -1834,7 +1834,7 @@ class CommandDrawBar : public SBarInfoCommand { sc.MustGetToken(TK_Identifier); type = AMMO; - inventoryItem = PClass::FindClass(sc.String); + inventoryItem = PClass::FindActor(sc.String); if(inventoryItem == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo { sc.ScriptError("'%s' is not a type of ammo.", sc.String); @@ -1854,8 +1854,8 @@ class CommandDrawBar : public SBarInfoCommand { type = POWERUPTIME; sc.MustGetToken(TK_Identifier); - inventoryItem = PClass::FindClass(sc.String); - if(inventoryItem == NULL || !PClass::FindClass("PowerupGiver")->IsAncestorOf(inventoryItem)) + inventoryItem = PClass::FindActor(sc.String); + if(inventoryItem == NULL || !RUNTIME_CLASS(APowerupGiver)->IsAncestorOf(inventoryItem)) { sc.ScriptError("'%s' is not a type of PowerupGiver.", sc.String); } @@ -1863,7 +1863,7 @@ class CommandDrawBar : public SBarInfoCommand else { type = INVENTORY; - inventoryItem = PClass::FindClass(sc.String); + inventoryItem = PClass::FindActor(sc.String); if(inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(inventoryItem)) { sc.ScriptError("'%s' is not a type of inventory item.", sc.String); @@ -2016,7 +2016,7 @@ class CommandDrawBar : public SBarInfoCommand { //Get the PowerupType and check to see if the player has any in inventory. APowerupGiver *powerupGiver = (APowerupGiver*) GetDefaultByType(inventoryItem); - const PClass *powerupType = powerupGiver->PowerupType; + PClassActor *powerupType = powerupGiver->PowerupType; APowerup *powerup = (APowerup*) statusBar->CPlayer->mo->FindInventory(powerupType); if(powerup != NULL && powerupType != NULL && powerupGiver != NULL) { @@ -2077,7 +2077,7 @@ class CommandDrawBar : public SBarInfoCommand int foreground; int background; ValueType type; - const PClass *inventoryItem; + PClassActor *inventoryItem; SBarInfoCoordinate x; SBarInfoCoordinate y; @@ -2507,7 +2507,7 @@ class CommandInInventory : public SBarInfoCommandFlowControl } for(int i = 0;i < 2;i++) { - item[i] = PClass::FindClass(sc.String); + item[i] = PClass::FindActor(sc.String); if(item[i] == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item[i])) sc.ScriptError("'%s' is not a type of inventory item.", sc.String); @@ -2535,7 +2535,7 @@ class CommandInInventory : public SBarInfoCommandFlowControl protected: bool conditionAnd; bool negate; - const PClass *item[2]; + PClassActor *item[2]; int amount[2]; }; diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 87664c204..d13fe3fe1 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -315,32 +315,33 @@ static void DrawArmor(AInventory * armor, int x, int y) // this doesn't have to be done each frame // //--------------------------------------------------------------------------- -static TArray<const PClass*> KeyTypes, UnassignedKeyTypes; +static TArray<PClassActor *> KeyTypes, UnassignedKeyTypes; static int STACK_ARGS ktcmp(const void * a, const void * b) { - AKey * key1 = (AKey*)GetDefaultByType ( *(const PClass**)a ); - AKey * key2 = (AKey*)GetDefaultByType ( *(const PClass**)b ); + AKey *key1 = (AKey*)GetDefaultByType ( *(PClassActor **)a ); + AKey *key2 = (AKey*)GetDefaultByType ( *(PClassActor **)b ); return key1->KeyNumber - key2->KeyNumber; } static void SetKeyTypes() { - for(unsigned int i=0;i<PClass::m_Types.Size();i++) + for(unsigned int i = 0; i < PClass::m_Types.Size(); i++) { - const PClass * ti = PClass::m_Types[i]; + PClass *ti = PClass::m_Types[i]; if (ti->IsDescendantOf(RUNTIME_CLASS(AKey))) { - AKey * key = (AKey*)GetDefaultByType(ti); + PClassActor *tia = static_cast<PClassActor *>(ti); + AKey *key = (AKey*)GetDefaultByType(tia); if (key->Icon.isValid() && key->KeyNumber>0) { - KeyTypes.Push(ti); + KeyTypes.Push(tia); } else { - UnassignedKeyTypes.Push(ti); + UnassignedKeyTypes.Push(tia); } } } @@ -351,7 +352,7 @@ static void SetKeyTypes() else { // Don't leave the list empty - const PClass * ti = RUNTIME_CLASS(AKey); + PClassActor *ti = RUNTIME_CLASS(AKey); KeyTypes.Push(ti); } } @@ -416,30 +417,30 @@ static int DrawKeys(player_t * CPlayer, int x, int y) int xo=x; int i; int c=0; - AInventory * inv; + AInventory *inv; if (!deathmatch) { - if (KeyTypes.Size()==0) SetKeyTypes(); + if (KeyTypes.Size() == 0) SetKeyTypes(); // First all keys that are assigned to locks (in reverse order of definition) - for(i=KeyTypes.Size()-1;i>=0;i--) + for (i = KeyTypes.Size()-1; i >= 0; i--) { - if ((inv=CPlayer->mo->FindInventory(KeyTypes[i]))) + if ((inv = CPlayer->mo->FindInventory(KeyTypes[i]))) { DrawOneKey(xo, x, y, c, inv); } } // And now the rest - for(i=UnassignedKeyTypes.Size()-1;i>=0;i--) + for (i = UnassignedKeyTypes.Size()-1; i >= 0; i--) { - if ((inv=CPlayer->mo->FindInventory(UnassignedKeyTypes[i]))) + if ((inv = CPlayer->mo->FindInventory(UnassignedKeyTypes[i]))) { DrawOneKey(xo, x, y, c, inv); } } } - if (x==xo && y!=yo) y+=11; + if (x == xo && y != yo) y+=11; return y-11; } @@ -449,14 +450,14 @@ static int DrawKeys(player_t * CPlayer, int x, int y) // Drawing Ammo // //--------------------------------------------------------------------------- -static TArray<const PClass *> orderedammos; +static TArray<PClassActor *> orderedammos; static void AddAmmoToList(AWeapon * weapdef) { for(int i=0; i<2;i++) { - const PClass * ti = i==0? weapdef->AmmoType1 : weapdef->AmmoType2; + PClassActor * ti = i==0? weapdef->AmmoType1 : weapdef->AmmoType2; if (ti) { AAmmo * ammodef=(AAmmo*)GetDefaultByType(ti); @@ -515,7 +516,7 @@ static int DrawAmmo(player_t *CPlayer, int x, int y) for(i=orderedammos.Size()-1;i>=0;i--) { - const PClass * type = orderedammos[i]; + PClassActor * type = orderedammos[i]; AAmmo * ammoitem = (AAmmo*)CPlayer->mo->FindInventory(type); AAmmo * inv = ammoitem? ammoitem : (AAmmo*)GetDefaultByType(orderedammos[i]); @@ -622,7 +623,7 @@ static void DrawWeapons(player_t * CPlayer, int x, int y) // And now everything in the weapon slots back to front for (k = NUM_WEAPON_SLOTS - 1; k >= 0; k--) for(j = CPlayer->weapons.Slots[k].Size() - 1; j >= 0; j--) { - const PClass *weap = CPlayer->weapons.Slots[k].GetWeapon(j); + PClassActor *weap = CPlayer->weapons.Slots[k].GetWeapon(j); if (weap) { inv=CPlayer->mo->FindInventory(weap); diff --git a/src/g_strife/a_strifeglobal.h b/src/g_strife/a_strifeglobal.h index d501485ba..8cc438d43 100644 --- a/src/g_strife/a_strifeglobal.h +++ b/src/g_strife/a_strifeglobal.h @@ -63,6 +63,6 @@ public: int NumPieces, DownPieces; }; -extern const PClass *QuestItemClasses[31]; +extern PClassActor *QuestItemClasses[31]; #endif diff --git a/src/g_strife/a_strifeitems.cpp b/src/g_strife/a_strifeitems.cpp index cd65b59ee..e5cc4136e 100644 --- a/src/g_strife/a_strifeitems.cpp +++ b/src/g_strife/a_strifeitems.cpp @@ -284,7 +284,7 @@ IMPLEMENT_CLASS (AAmmoFillup) bool AAmmoFillup::TryPickup (AActor *&toucher) { - const PClass * clip = PClass::FindClass(NAME_ClipOfBullets); + PClassActor *clip = PClass::FindActor(NAME_ClipOfBullets); if (clip != NULL) { AInventory *item = toucher->FindInventory(clip); diff --git a/src/g_strife/a_thingstoblowup.cpp b/src/g_strife/a_thingstoblowup.cpp index 797b9af97..d79801c36 100644 --- a/src/g_strife/a_thingstoblowup.cpp +++ b/src/g_strife/a_thingstoblowup.cpp @@ -14,8 +14,6 @@ static FRandom pr_bang4cloud ("Bang4Cloud"); static FRandom pr_lightout ("LightOut"); -extern const PClass *QuestItemClasses[31]; - DEFINE_ACTION_FUNCTION(AActor, A_Bang4Cloud) { PARAM_ACTION_PROLOGUE; diff --git a/src/g_strife/strife_sbar.cpp b/src/g_strife/strife_sbar.cpp index a7155b679..311ea07c3 100644 --- a/src/g_strife/strife_sbar.cpp +++ b/src/g_strife/strife_sbar.cpp @@ -706,7 +706,7 @@ private: }; for (i = 0; i < 7; ++i) { - const PClass *ammotype = PClass::FindClass(AmmoList[i].AmmoType); + PClassActor *ammotype = PClass::FindActor(AmmoList[i].AmmoType); item = CPlayer->mo->FindInventory (ammotype); if (item == NULL) diff --git a/src/info.cpp b/src/info.cpp index 99110737c..4f666b767 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -107,13 +107,15 @@ int GetSpriteIndex(const char * spritename) return (lastindex = (int)sprites.Push (temp)); } +IMPLEMENT_CLASS(PClassActor) //========================================================================== // +// PClassActor :: StaticInit STATIC // //========================================================================== -void FActorInfo::StaticInit () +void PClassActor::StaticInit() { if (sprites.Size() == 0) { @@ -136,56 +138,161 @@ void FActorInfo::StaticInit () //========================================================================== // +// PClassActor :: StaticSetActorNums STATIC +// // Called after Dehacked patches are applied // //========================================================================== -void FActorInfo::StaticSetActorNums () +void PClassActor::StaticSetActorNums() { - memset (SpawnableThings, 0, sizeof(SpawnableThings)); - DoomEdMap.Empty (); + memset(SpawnableThings, 0, sizeof(SpawnableThings)); + DoomEdMap.Empty(); for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i) { - PClass::m_RuntimeActors[i]->ActorInfo->RegisterIDs (); + static_cast<PClassActor *>(PClass::m_RuntimeActors[i])->RegisterIDs(); } } //========================================================================== // +// PClassActor Constructor // //========================================================================== -void FActorInfo::RegisterIDs () +PClassActor::PClassActor() { - const PClass *cls = PClass::FindClass(Class->TypeName); + GameFilter = GAME_Any; + SpawnID = 0; + DoomEdNum = -1; + OwnedStates = NULL; + NumOwnedStates = 0; + Replacement = NULL; + Replacee = NULL; + StateList = NULL; + DamageFactors = NULL; + PainChances = NULL; +} + +//========================================================================== +// +// PClassActor Destructor +// +//========================================================================== + +PClassActor::~PClassActor() +{ + if (OwnedStates != NULL) + { + delete[] OwnedStates; + } + if (DamageFactors != NULL) + { + delete DamageFactors; + } + if (PainChances != NULL) + { + delete PainChances; + } + if (StateList != NULL) + { + StateList->Destroy(); + M_Free(StateList); + } +} + +//========================================================================== +// +// PClassActor :: PropagateMark +// +//========================================================================== + +size_t PClassActor::PropagateMark() +{ + // Mark state functions + for (int i = 0; i < NumOwnedStates; ++i) + { + if (OwnedStates[i].ActionFunc != NULL) + { + GC::Mark(OwnedStates[i].ActionFunc); + } + } +// marked += ActorInfo->NumOwnedStates * sizeof(FState); + return Super::PropagateMark(); +} + +//========================================================================== +// +// PClassActor :: InitializeNativeDefaults +// +// This is used by DECORATE to assign ActorInfos to internal classes +// +//========================================================================== + +void PClassActor::InitializeNativeDefaults() +{ + Symbols.SetParentTable(&ParentClass->Symbols); + assert(Defaults == NULL); + Defaults = new BYTE[Size]; + if (ParentClass->Defaults != NULL) + { + memcpy(Defaults, ParentClass->Defaults, ParentClass->Size); + if (Size > ParentClass->Size) + { + memset(Defaults + ParentClass->Size, 0, Size - ParentClass->Size); + } + } + else + { + memset (Defaults, 0, Size); + } + m_RuntimeActors.Push(this); +} + +//========================================================================== +// +// PClassActor :: RegisterIDs +// +// Registers this class's SpawnID and DoomEdNum in the appropriate tables. +// +//========================================================================== + +void PClassActor::RegisterIDs() +{ + PClassActor *cls = PClass::FindActor(TypeName); bool set = false; + if (cls == NULL) + { + Printf(TEXTCOLOR_RED"The actor '%s' has been hidden by a non-actor of the same name\n", TypeName.GetChars()); + return; + } + if (GameFilter == GAME_Any || (GameFilter & gameinfo.gametype)) { if (SpawnID != 0) { SpawnableThings[SpawnID] = cls; - if (cls != Class) + if (cls != this) { Printf(TEXTCOLOR_RED"Spawn ID %d refers to hidden class type '%s'\n", SpawnID, cls->TypeName.GetChars()); } } if (DoomEdNum != -1) { - DoomEdMap.AddType (DoomEdNum, cls); - if (cls != Class) + DoomEdMap.AddType(DoomEdNum, cls); + if (cls != this) { Printf(TEXTCOLOR_RED"Editor number %d refers to hidden class type '%s'\n", DoomEdNum, cls->TypeName.GetChars()); } } } // Fill out the list for Chex Quest with Doom's actors - if (gameinfo.gametype == GAME_Chex && DoomEdMap.FindType(DoomEdNum) == NULL && - (GameFilter & GAME_Doom)) + if (gameinfo.gametype == GAME_Chex && DoomEdMap.FindType(DoomEdNum) == NULL && (GameFilter & GAME_Doom)) { - DoomEdMap.AddType (DoomEdNum, Class, true); - if (cls != Class) + DoomEdMap.AddType(DoomEdNum, this, true); + if (cls != this) { Printf(TEXTCOLOR_RED"Editor number %d refers to hidden class type '%s'\n", DoomEdNum, cls->TypeName.GetChars()); } @@ -194,24 +301,25 @@ void FActorInfo::RegisterIDs () //========================================================================== // +// PClassActor :: GetReplacement // //========================================================================== -FActorInfo *FActorInfo::GetReplacement (bool lookskill) +PClassActor *PClassActor::GetReplacement(bool lookskill) { FName skillrepname; if (lookskill && AllSkills.Size() > (unsigned)gameskill) { - skillrepname = AllSkills[gameskill].GetReplacement(this->Class->TypeName); + skillrepname = AllSkills[gameskill].GetReplacement(TypeName); if (skillrepname != NAME_None && PClass::FindClass(skillrepname) == NULL) { Printf("Warning: incorrect actor name in definition of skill %s: \n" "class %s is replaced by non-existent class %s\n" "Skill replacement will be ignored for this actor.\n", AllSkills[gameskill].Name.GetChars(), - this->Class->TypeName.GetChars(), skillrepname.GetChars()); - AllSkills[gameskill].SetReplacement(this->Class->TypeName, NAME_None); + TypeName.GetChars(), skillrepname.GetChars()); + AllSkills[gameskill].SetReplacement(TypeName, NAME_None); AllSkills[gameskill].SetReplacedBy(skillrepname, NAME_None); lookskill = false; skillrepname = NAME_None; } @@ -222,15 +330,15 @@ FActorInfo *FActorInfo::GetReplacement (bool lookskill) } // The Replacement field is temporarily NULLed to prevent // potential infinite recursion. - FActorInfo *savedrep = Replacement; + PClassActor *savedrep = Replacement; Replacement = NULL; - FActorInfo *rep = savedrep; + PClassActor *rep = savedrep; // Handle skill-based replacement here. It has precedence on DECORATE replacement // in that the skill replacement is applied first, followed by DECORATE replacement // on the actor indicated by the skill replacement. if (lookskill && (skillrepname != NAME_None)) { - rep = PClass::FindClass(skillrepname)->ActorInfo; + rep = PClass::FindActor(skillrepname); } // Now handle DECORATE replacement chain // Skill replacements are not recursive, contrarily to DECORATE replacements @@ -242,24 +350,25 @@ FActorInfo *FActorInfo::GetReplacement (bool lookskill) //========================================================================== // +// PClassActor :: GetReplacee // //========================================================================== -FActorInfo *FActorInfo::GetReplacee (bool lookskill) +PClassActor *PClassActor::GetReplacee(bool lookskill) { FName skillrepname; if (lookskill && AllSkills.Size() > (unsigned)gameskill) { - skillrepname = AllSkills[gameskill].GetReplacedBy(this->Class->TypeName); + skillrepname = AllSkills[gameskill].GetReplacedBy(TypeName); if (skillrepname != NAME_None && PClass::FindClass(skillrepname) == NULL) { Printf("Warning: incorrect actor name in definition of skill %s: \n" "non-existent class %s is replaced by class %s\n" "Skill replacement will be ignored for this actor.\n", AllSkills[gameskill].Name.GetChars(), - skillrepname.GetChars(), this->Class->TypeName.GetChars()); - AllSkills[gameskill].SetReplacedBy(this->Class->TypeName, NAME_None); + skillrepname.GetChars(), TypeName.GetChars()); + AllSkills[gameskill].SetReplacedBy(TypeName, NAME_None); AllSkills[gameskill].SetReplacement(skillrepname, NAME_None); lookskill = false; } @@ -270,52 +379,59 @@ FActorInfo *FActorInfo::GetReplacee (bool lookskill) } // The Replacee field is temporarily NULLed to prevent // potential infinite recursion. - FActorInfo *savedrep = Replacee; + PClassActor *savedrep = Replacee; Replacee = NULL; - FActorInfo *rep = savedrep; + PClassActor *rep = savedrep; if (lookskill && (skillrepname != NAME_None) && (PClass::FindClass(skillrepname) != NULL)) { - rep = PClass::FindClass(skillrepname)->ActorInfo; + rep = PClass::FindActor(skillrepname); } - rep = rep->GetReplacee (false); Replacee = savedrep; + rep = rep->GetReplacee(false); + Replacee = savedrep; return rep; } //========================================================================== // +// PClassActor :: SetDamageFactor // //========================================================================== -void FActorInfo::SetDamageFactor(FName type, fixed_t factor) +void PClassActor::SetDamageFactor(FName type, fixed_t factor) { if (factor != FRACUNIT) { - if (DamageFactors == NULL) DamageFactors=new DmgFactors; + if (DamageFactors == NULL) + { + DamageFactors = new DmgFactors; + } DamageFactors->Insert(type, factor); } - else + else if (DamageFactors != NULL) { - if (DamageFactors != NULL) - DamageFactors->Remove(type); + DamageFactors->Remove(type); } } //========================================================================== // +// PClassActor :: SetPainChance // //========================================================================== -void FActorInfo::SetPainChance(FName type, int chance) +void PClassActor::SetPainChance(FName type, int chance) { if (chance >= 0) { - if (PainChances == NULL) PainChances=new PainChanceList; + if (PainChances == NULL) + { + PainChances = new PainChanceList; + } PainChances->Insert(type, MIN(chance, 255)); } - else + else if (PainChances != NULL) { - if (PainChances != NULL) - PainChances->Remove(type); + PainChances->Remove(type); } } @@ -333,7 +449,7 @@ FDoomEdMap::~FDoomEdMap() Empty(); } -void FDoomEdMap::AddType (int doomednum, const PClass *type, bool temporary) +void FDoomEdMap::AddType (int doomednum, PClassActor *type, bool temporary) { unsigned int hash = (unsigned int)doomednum % DOOMED_HASHSIZE; FDoomEdEntry *entry = DoomEdHash[hash]; @@ -392,7 +508,7 @@ void FDoomEdMap::Empty () } } -const PClass *FDoomEdMap::FindType (int doomednum) const +PClassActor *FDoomEdMap::FindType (int doomednum) const { unsigned int hash = (unsigned int)doomednum % DOOMED_HASHSIZE; FDoomEdEntry *entry = DoomEdHash[hash]; diff --git a/src/info.h b/src/info.h index 8cc381601..ebc2f1250 100644 --- a/src/info.h +++ b/src/info.h @@ -94,8 +94,8 @@ struct FState } void SetAction(VMFunction *func) { ActionFunc = func; } bool CallAction(AActor *self, AActor *stateowner, StateCallData *statecall = NULL); - static const PClass *StaticFindStateOwner (const FState *state); - static const PClass *StaticFindStateOwner (const FState *state, const FActorInfo *info); + static const PClassActor *StaticFindStateOwner (const FState *state); + static const PClassActor *StaticFindStateOwner (const FState *state, const PClassActor *info); }; struct FStateLabels; @@ -125,47 +125,58 @@ FArchive &operator<< (FArchive &arc, FState *&state); typedef TMap<FName, fixed_t> DmgFactors; typedef TMap<FName, BYTE> PainChanceList; -struct FActorInfo +class PClassActor : public PClass { + DECLARE_CLASS(PClassActor, PClass); +public: static void StaticInit (); static void StaticSetActorNums (); - void BuildDefaults (); - void ApplyDefaults (BYTE *defaults); - void RegisterIDs (); + PClassActor(); + ~PClassActor(); + + void BuildDefaults(); + void ApplyDefaults(BYTE *defaults); + void RegisterIDs(); void SetDamageFactor(FName type, fixed_t factor); void SetPainChance(FName type, int chance); + size_t PropagateMark(); + void InitializeNativeDefaults(); - FState *FindState (int numnames, FName *names, bool exact=false) const; + FState *FindState(int numnames, FName *names, bool exact=false) const; FState *FindStateByString(const char *name, bool exact=false); - FState *FindState (FName name) const + FState *FindState(FName name) const { return FindState(1, &name); } - FActorInfo *GetReplacement (bool lookskill=true); - FActorInfo *GetReplacee (bool lookskill=true); + PClassActor *GetReplacement(bool lookskill=true); + PClassActor *GetReplacee(bool lookskill=true); - PClass *Class; FState *OwnedStates; - FActorInfo *Replacement; - FActorInfo *Replacee; + PClassActor *Replacement; + PClassActor *Replacee; int NumOwnedStates; BYTE GameFilter; BYTE SpawnID; SWORD DoomEdNum; - FStateLabels * StateList; + FStateLabels *StateList; DmgFactors *DamageFactors; - PainChanceList * PainChances; + PainChanceList *PainChances; }; +inline PClassActor *PClass::FindActor(FName name) +{ + return dyn_cast<PClassActor>(FindClass(name)); +} + class FDoomEdMap { public: ~FDoomEdMap(); - const PClass *FindType (int doomednum) const; - void AddType (int doomednum, const PClass *type, bool temporary = false); + PClassActor *FindType (int doomednum) const; + void AddType (int doomednum, PClassActor *type, bool temporary = false); void DelType (int doomednum); void Empty (); @@ -177,7 +188,7 @@ private: struct FDoomEdEntry { FDoomEdEntry *HashNext; - const PClass *Type; + PClassActor *Type; int DoomEdNum; bool temp; }; diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index b82b2fca8..abf2983ae 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -52,19 +52,19 @@ void cht_DoCheat (player_t *player, int cheat) { - static const PClass *const *BeholdPowers[9] = + static PClass *const *BeholdPowers[9] = { - &RUNTIME_CLASS(APowerInvulnerable), - &RUNTIME_CLASS(APowerStrength), - &RUNTIME_CLASS(APowerInvisibility), - &RUNTIME_CLASS(APowerIronFeet), + &RUNTIME_CLASS_CASTLESS(APowerInvulnerable), + &RUNTIME_CLASS_CASTLESS(APowerStrength), + &RUNTIME_CLASS_CASTLESS(APowerInvisibility), + &RUNTIME_CLASS_CASTLESS(APowerIronFeet), NULL, // MapRevealer - &RUNTIME_CLASS(APowerLightAmp), - &RUNTIME_CLASS(APowerShadow), - &RUNTIME_CLASS(APowerMask), - &RUNTIME_CLASS(APowerTargeter) + &RUNTIME_CLASS_CASTLESS(APowerLightAmp), + &RUNTIME_CLASS_CASTLESS(APowerShadow), + &RUNTIME_CLASS_CASTLESS(APowerMask), + &RUNTIME_CLASS_CASTLESS(APowerTargeter) }; - const PClass *type; + PClassActor *type; AInventory *item; const char *msg = ""; char msgbuild[32]; @@ -175,15 +175,12 @@ void cht_DoCheat (player_t *player, int cheat) case CHT_CHAINSAW: if (player->mo != NULL && player->health >= 0) { - type = PClass::FindClass ("Chainsaw"); + type = PClass::FindActor("Chainsaw"); if (player->mo->FindInventory (type) == NULL) { player->mo->GiveInventoryType (type); } - if(gameinfo.gametype != GAME_Chex) - msg = GStrings("STSTR_CHOPPERS"); - else - msg = GStrings("STSTR_CCHOPPERS"); + msg = GStrings(gameinfo.gametype != GAME_Chex ? "STSTR_CHOPPERS" : "STSTR_CCHOPPERS"); } // [RH] The original cheat also set powers[pw_invulnerability] to true. // Since this is a timer and not a boolean, it effectively turned off @@ -248,7 +245,7 @@ void cht_DoCheat (player_t *player, int cheat) } else if (player->mo != NULL && player->health >= 0) { - item = player->mo->FindInventory (*BeholdPowers[i]); + item = player->mo->FindInventory(static_cast<PClassActor *>(*BeholdPowers[i])); if (item == NULL) { if (i != 0) @@ -262,7 +259,7 @@ void cht_DoCheat (player_t *player, int cheat) else { // Let's give the item here so that the power doesn't need colormap information. - player->mo->GiveInventoryType(PClass::FindClass("InvulnerabilitySphere")); + player->mo->GiveInventoryType(PClass::FindActor("InvulnerabilitySphere")); } } else @@ -603,7 +600,7 @@ void cht_Give (player_t *player, const char *name, int amount) { bool giveall; int i; - const PClass *type; + PClass *type; if (player != &players[consoleplayer]) Printf ("%s is a cheater: give %s\n", player->userinfo.netname, name); @@ -664,11 +661,11 @@ void cht_Give (player_t *player, const char *name, int amount) // he doesn't have it already, and set each to its maximum. for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) { - const PClass *type = PClass::m_Types[i]; + PClass *type = PClass::m_Types[i]; if (type->ParentClass == RUNTIME_CLASS(AAmmo)) { - AInventory *ammo = player->mo->FindInventory (type); + AInventory *ammo = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (ammo == NULL) { ammo = static_cast<AInventory *>(Spawn (type, 0, 0, 0, NO_REPLACE)); @@ -746,15 +743,14 @@ void cht_Give (player_t *player, const char *name, int amount) // Don't give replaced weapons unless the replacement was done by Dehacked. if (type != RUNTIME_CLASS(AWeapon) && type->IsDescendantOf (RUNTIME_CLASS(AWeapon)) && - (type->ActorInfo->GetReplacement() == type->ActorInfo || - type->ActorInfo->GetReplacement()->Class->IsDescendantOf(RUNTIME_CLASS(ADehackedPickup)))) - + (static_cast<PClassActor *>(type)->GetReplacement() == type || + static_cast<PClassActor *>(type)->GetReplacement()->IsDescendantOf(RUNTIME_CLASS(ADehackedPickup)))) { // Give the weapon only if it belongs to the current game or // is in a weapon slot. - if (type->ActorInfo->GameFilter == GAME_Any || - (type->ActorInfo->GameFilter & gameinfo.gametype) || - player->weapons.LocateWeapon(type, NULL, NULL)) + if (static_cast<PClassActor *>(type)->GameFilter == GAME_Any || + (static_cast<PClassActor *>(type)->GameFilter & gameinfo.gametype) || + player->weapons.LocateWeapon(static_cast<PClassActor *>(type), NULL, NULL)) { AWeapon *def = (AWeapon*)GetDefaultByType (type); if (!(def->WeaponFlags & WIF_CHEATNOTWEAPON)) @@ -828,7 +824,7 @@ void cht_Give (player_t *player, const char *name, int amount) void cht_Take (player_t *player, const char *name, int amount) { bool takeall; - const PClass *type; + PClass *type; if (player->mo == NULL || player->health <= 0) { @@ -874,13 +870,14 @@ void cht_Take (player_t *player, const char *name, int amount) // Take away all types of backpacks the player might own. for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) { - const PClass *type = PClass::m_Types[i]; + PClass *type = PClass::m_Types[i]; if (type->IsDescendantOf(RUNTIME_CLASS (ABackpackItem))) { - AInventory *pack = player->mo->FindInventory (type); + AInventory *pack = player->mo->FindInventory(static_cast<PClassActor *>(type)); - if (pack) pack->Destroy(); + if (pack) + pack->Destroy(); } } @@ -892,11 +889,11 @@ void cht_Take (player_t *player, const char *name, int amount) { for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) { - const PClass *type = PClass::m_Types[i]; + PClass *type = PClass::m_Types[i]; if (type->ParentClass == RUNTIME_CLASS (AAmmo)) { - AInventory *ammo = player->mo->FindInventory (type); + AInventory *ammo = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (ammo) ammo->Amount = 0; @@ -915,7 +912,7 @@ void cht_Take (player_t *player, const char *name, int amount) if (type->IsDescendantOf (RUNTIME_CLASS (AArmor))) { - AActor *armor = player->mo->FindInventory (type); + AActor *armor = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (armor) armor->Destroy (); @@ -934,7 +931,7 @@ void cht_Take (player_t *player, const char *name, int amount) if (type->IsDescendantOf (RUNTIME_CLASS (AKey))) { - AActor *key = player->mo->FindInventory (type); + AActor *key = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (key) key->Destroy (); @@ -954,7 +951,7 @@ void cht_Take (player_t *player, const char *name, int amount) if (type != RUNTIME_CLASS(AWeapon) && type->IsDescendantOf (RUNTIME_CLASS (AWeapon))) { - AActor *weapon = player->mo->FindInventory (type); + AActor *weapon = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (weapon) weapon->Destroy (); @@ -984,7 +981,7 @@ void cht_Take (player_t *player, const char *name, int amount) !type->IsDescendantOf (RUNTIME_CLASS (AWeapon)) && !type->IsDescendantOf (RUNTIME_CLASS (AKey))) { - AActor *artifact = player->mo->FindInventory (type); + AActor *artifact = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (artifact) artifact->Destroy (); @@ -1004,7 +1001,7 @@ void cht_Take (player_t *player, const char *name, int amount) if (type->IsDescendantOf (RUNTIME_CLASS (APuzzleItem))) { - AActor *puzzlepiece = player->mo->FindInventory (type); + AActor *puzzlepiece = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (puzzlepiece) puzzlepiece->Destroy (); @@ -1026,7 +1023,7 @@ void cht_Take (player_t *player, const char *name, int amount) } else { - AInventory *inventory = player->mo->FindInventory (type); + AInventory *inventory = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (inventory != NULL) { @@ -1055,7 +1052,10 @@ void cht_Suicide (player_t *plyr) plyr->mo->flags |= MF_SHOOTABLE; plyr->mo->flags2 &= ~MF2_INVULNERABLE; P_DamageMobj (plyr->mo, plyr->mo, plyr->mo, TELEFRAG_DAMAGE, NAME_Suicide); - if (plyr->mo->health <= 0) plyr->mo->flags &= ~MF_SHOOTABLE; + if (plyr->mo->health <= 0) + { + plyr->mo->flags &= ~MF_SHOOTABLE; + } } } diff --git a/src/p_acs.cpp b/src/p_acs.cpp index c899c5844..7afc750f7 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -520,7 +520,7 @@ static void GiveInventory (AActor *activator, const char *type, int amount) // //============================================================================ -static void DoTakeInv (AActor *actor, const PClass *info, int amount) +static void DoTakeInv (AActor *actor, PClassActor *info, int amount) { AInventory *item = actor->FindInventory (info); if (item != NULL) @@ -556,7 +556,7 @@ static void DoTakeInv (AActor *actor, const PClass *info, int amount) static void TakeInventory (AActor *activator, const char *type, int amount) { - const PClass *info; + PClassActor *info; if (type == NULL) { @@ -570,7 +570,7 @@ static void TakeInventory (AActor *activator, const char *type, int amount) { return; } - info = PClass::FindClass (type); + info = PClass::FindActor (type); if (info == NULL) { return; @@ -597,7 +597,7 @@ static void TakeInventory (AActor *activator, const char *type, int amount) // //============================================================================ -static bool DoUseInv (AActor *actor, const PClass *info) +static bool DoUseInv (AActor *actor, PClassActor *info) { AInventory *item = actor->FindInventory (info); if (item != NULL) @@ -617,14 +617,14 @@ static bool DoUseInv (AActor *actor, const PClass *info) static int UseInventory (AActor *activator, const char *type) { - const PClass *info; + PClassActor *info; int ret = 0; if (type == NULL) { return 0; } - info = PClass::FindClass (type); + info = PClass::FindActor (type); if (info == NULL) { return 0; @@ -666,7 +666,7 @@ static int CheckInventory (AActor *activator, const char *type) return activator->health; } - const PClass *info = PClass::FindClass (type); + PClassActor *info = PClass::FindActor (type); AInventory *item = activator->FindInventory (info); return item ? item->Amount : 0; } @@ -2060,7 +2060,7 @@ int DLevelScript::Random (int min, int max) int DLevelScript::ThingCount (int type, int stringid, int tid, int tag) { AActor *actor; - const PClass *kind; + PClassActor *kind; int count = 0; bool replacemented = false; @@ -2080,10 +2080,9 @@ int DLevelScript::ThingCount (int type, int stringid, int tid, int tag) if (type_name == NULL) return 0; - kind = PClass::FindClass (type_name); - if (kind == NULL || kind->ActorInfo == NULL) + kind = PClass::FindActor(type_name); + if (kind == NULL) return 0; - } else { @@ -2135,7 +2134,7 @@ do_count: { // Again, with decorate replacements replacemented = true; - PClass *newkind = kind->ActorInfo->GetReplacement()->Class; + PClassActor *newkind = kind->GetReplacement(); if (newkind != kind) { kind = newkind; @@ -5500,12 +5499,12 @@ int DLevelScript::RunScript () case PCD_GETAMMOCAPACITY: if (activator != NULL) { - const PClass *type = PClass::FindClass (FBehavior::StaticLookupString (STACK(1))); + PClass *type = PClass::FindClass (FBehavior::StaticLookupString (STACK(1))); AInventory *item; if (type != NULL && type->ParentClass == RUNTIME_CLASS(AAmmo)) { - item = activator->FindInventory (type); + item = activator->FindInventory (static_cast<PClassActor *>(type)); if (item != NULL) { STACK(1) = item->MaxAmount; @@ -5529,12 +5528,12 @@ int DLevelScript::RunScript () case PCD_SETAMMOCAPACITY: if (activator != NULL) { - const PClass *type = PClass::FindClass (FBehavior::StaticLookupString (STACK(2))); + PClass *type = PClass::FindClass (FBehavior::StaticLookupString (STACK(2))); AInventory *item; if (type != NULL && type->ParentClass == RUNTIME_CLASS(AAmmo)) { - item = activator->FindInventory (type); + item = activator->FindInventory (static_cast<PClassActor *>(type)); if (item != NULL) { item->MaxAmount = STACK(1); @@ -5835,8 +5834,8 @@ int DLevelScript::RunScript () } else { - AInventory *item = activator->FindInventory (PClass::FindClass ( - FBehavior::StaticLookupString (STACK(1)))); + AInventory *item = activator->FindInventory (dyn_cast<PClassActor>( + PClass::FindClass (FBehavior::StaticLookupString (STACK(1))))); if (item == NULL || !item->IsKindOf (RUNTIME_CLASS(AWeapon))) { @@ -6149,7 +6148,7 @@ int DLevelScript::RunScript () { if (activator != NULL) { - state = activator->GetClass()->ActorInfo->FindStateByString (statename, !!STACK(1)); + state = activator->GetClass()->FindStateByString (statename, !!STACK(1)); if (state != NULL) { activator->SetState (state); @@ -6169,7 +6168,7 @@ int DLevelScript::RunScript () while ( (actor = iterator.Next ()) ) { - state = actor->GetClass()->ActorInfo->FindStateByString (statename, !!STACK(1)); + state = actor->GetClass()->FindStateByString (statename, !!STACK(1)); if (state != NULL) { actor->SetState (state); @@ -6235,7 +6234,7 @@ int DLevelScript::RunScript () int amount = STACK(4); FName type = FBehavior::StaticLookupString(STACK(3)); FName protection = FName (FBehavior::StaticLookupString(STACK(2)), true); - const PClass *protectClass = PClass::FindClass (protection); + PClassActor *protectClass = PClass::FindActor (protection); int flags = STACK(1); sp -= 5; diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 8e32ee8ab..614d6e4b1 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -107,7 +107,7 @@ TArray<FStrifeDialogueNode *> StrifeDialogues; // to their index in the mobjinfo table. This table indexes all // the Strife actor types in the order Strife had them and is // initialized as part of the actor's setup in infodefaults.cpp. -const PClass *StrifeTypes[1001]; +PClass *StrifeTypes[1001]; static menu_t ConversationMenu; static TArray<menuitem_t> ConversationItems; @@ -139,7 +139,7 @@ static FBrokenLines *DialogueLines; // //============================================================================ -static const PClass *GetStrifeType (int typenum) +static PClass *GetStrifeType (int typenum) { if (typenum > 0 && typenum < 1001) { @@ -342,12 +342,12 @@ static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, DWORD &prevSpeaker node->SpeakerName = ncopystring (speech.Name); // The item the speaker should drop when killed. - node->DropType = GetStrifeType (speech.DropType); + node->DropType = dyn_cast<PClassActor>(GetStrifeType (speech.DropType)); // Items you need to have to make the speaker use a different node. for (j = 0; j < 3; ++j) { - node->ItemCheck[j] = GetStrifeType (speech.ItemCheck[j]); + node->ItemCheck[j] = dyn_cast<PClassActor>(GetStrifeType (speech.ItemCheck[j])); } node->ItemCheckNode = speech.Link; node->Children = NULL; @@ -416,7 +416,7 @@ static FStrifeDialogueNode *ReadTeaserNode (FileReader *lump, DWORD &prevSpeaker node->SpeakerName = ncopystring (speech.Name); // The item the speaker should drop when killed. - node->DropType = GetStrifeType (speech.DropType); + node->DropType = dyn_cast<PClassActor>(GetStrifeType (speech.DropType)); // Items you need to have to make the speaker use a different node. for (j = 0; j < 3; ++j) @@ -478,12 +478,12 @@ static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses) reply->LogNumber = rsp->Log; // The item to receive when this reply is used. - reply->GiveType = GetStrifeType (rsp->GiveType); + reply->GiveType = dyn_cast<PClassActor>(GetStrifeType (rsp->GiveType)); // Do you need anything special for this reply to succeed? for (k = 0; k < 3; ++k) { - reply->ItemCheck[k] = GetStrifeType (rsp->Item[k]); + reply->ItemCheck[k] = dyn_cast<PClassActor>(GetStrifeType (rsp->Item[k])); reply->ItemCheckAmount[k] = rsp->Count[k]; } @@ -592,7 +592,7 @@ static int FindNode (const FStrifeDialogueNode *node) // //============================================================================ -static bool CheckStrifeItem (player_t *player, const PClass *itemtype, int amount=-1) +static bool CheckStrifeItem (player_t *player, PClassActor *itemtype, int amount=-1) { AInventory *item; @@ -615,7 +615,7 @@ static bool CheckStrifeItem (player_t *player, const PClass *itemtype, int amoun // //============================================================================ -static void TakeStrifeItem (player_t *player, const PClass *itemtype, int amount) +static void TakeStrifeItem (player_t *player, PClassActor *itemtype, int amount) { if (itemtype == NULL || amount == 0) return; diff --git a/src/p_conversation.h b/src/p_conversation.h index 13658e0f0..804f6b913 100644 --- a/src/p_conversation.h +++ b/src/p_conversation.h @@ -15,8 +15,8 @@ struct FBrokenLines; struct FStrifeDialogueNode { ~FStrifeDialogueNode (); - const PClass *DropType; - const PClass *ItemCheck[3]; + PClassActor *DropType; + PClassActor *ItemCheck[3]; int ThisNodeNum; // location of this node in StrifeDialogues int ItemCheckNode; // index into StrifeDialogues @@ -35,8 +35,8 @@ struct FStrifeDialogueReply ~FStrifeDialogueReply (); FStrifeDialogueReply *Next; - const PClass *GiveType; - const PClass *ItemCheck[3]; + PClassActor *GiveType; + PClassActor *ItemCheck[3]; int ItemCheckAmount[3]; char *Reply; char *QuickYes; @@ -54,7 +54,7 @@ extern TArray<FStrifeDialogueNode *> StrifeDialogues; // to their index in the mobjinfo table. This table indexes all // the Strife actor types in the order Strife had them and is // initialized as part of the actor's setup in infodefaults.cpp. -extern const PClass *StrifeTypes[1001]; +extern PClass *StrifeTypes[1001]; struct MapData; diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index f73a17eda..cd94bf76d 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -2548,10 +2548,10 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates) { // For Dehacked compatibility this has to use the Arch Vile's // heal state as a default if the actor doesn't define one itself. - const PClass *archvile = PClass::FindClass("Archvile"); + const PClassActor *archvile = PClass::FindActor("Archvile"); if (archvile != NULL) { - self->SetState (archvile->ActorInfo->FindState(NAME_Heal)); + self->SetState (archvile->FindState(NAME_Heal)); } } S_Sound (corpsehit, CHAN_BODY, "vile/raise", 1, ATTN_IDLE); @@ -3084,11 +3084,11 @@ void A_BossDeath(AActor *self) FName mytype = self->GetClass()->TypeName; // Ugh... - FName type = self->GetClass()->ActorInfo->GetReplacee()->Class->TypeName; + FName type = self->GetClass()->GetReplacee()->TypeName; // Do generic special death actions first bool checked = false; - for(unsigned i=0; i<level.info->specialactions.Size(); i++) + for (unsigned i = 0; i < level.info->specialactions.Size(); i++) { FSpecialAction *sa = &level.info->specialactions[i]; diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 24d6cfd83..3952251a2 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1005,11 +1005,14 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage if (!(flags & DMG_NO_FACTOR)) { - DmgFactors *df = target->GetClass()->ActorInfo->DamageFactors; + DmgFactors *df = target->GetClass()->DamageFactors; if (df != NULL) { fixed_t *pdf = df->CheckKey(mod); - if (pdf== NULL && mod != NAME_None) pdf = df->CheckKey(NAME_None); + if (pdf== NULL && mod != NAME_None) + { + pdf = df->CheckKey(NAME_None); + } if (pdf != NULL) { damage = FixedMul(damage, *pdf); @@ -1281,7 +1284,7 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage if (!(target->flags5 & MF5_NOPAIN) && (inflictor == NULL || !(inflictor->flags5 & MF5_PAINLESS)) && !G_SkillProperty(SKILLP_NoPain) && !(target->flags & MF_SKULLFLY)) { - pc = target->GetClass()->ActorInfo->PainChances; + pc = target->GetClass()->PainChances; painchance = target->PainChance; if (pc != NULL) { diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 947d1069b..4dda3cc24 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -2529,19 +2529,19 @@ FUNC(LS_SetPlayerProperty) // Add or remove a power if (arg2 >= PROP_INVULNERABILITY && arg2 <= PROP_SPEED) { - static const PClass * const *powers[11] = + static PClass * const *powers[11] = { - &RUNTIME_CLASS(APowerInvulnerable), - &RUNTIME_CLASS(APowerStrength), - &RUNTIME_CLASS(APowerInvisibility), - &RUNTIME_CLASS(APowerIronFeet), + &RUNTIME_CLASS_CASTLESS(APowerInvulnerable), + &RUNTIME_CLASS_CASTLESS(APowerStrength), + &RUNTIME_CLASS_CASTLESS(APowerInvisibility), + &RUNTIME_CLASS_CASTLESS(APowerIronFeet), NULL, // MapRevealer - &RUNTIME_CLASS(APowerLightAmp), - &RUNTIME_CLASS(APowerWeaponLevel2), - &RUNTIME_CLASS(APowerFlight), + &RUNTIME_CLASS_CASTLESS(APowerLightAmp), + &RUNTIME_CLASS_CASTLESS(APowerWeaponLevel2), + &RUNTIME_CLASS_CASTLESS(APowerFlight), NULL, NULL, - &RUNTIME_CLASS(APowerSpeed) + &RUNTIME_CLASS_CASTLESS(APowerSpeed) }; int power = arg2 - PROP_INVULNERABILITY; @@ -2571,7 +2571,7 @@ FUNC(LS_SetPlayerProperty) { // Take power from activator if (power != 4) { - AInventory *item = it->FindInventory (*powers[power]); + AInventory *item = it->FindInventory (static_cast<PClassActor *>(*powers[power])); if (item != NULL) { item->Destroy (); @@ -2596,7 +2596,7 @@ FUNC(LS_SetPlayerProperty) { // Give power if (power != 4) { - APowerup *item = static_cast<APowerup*>(players[i].mo->GiveInventoryType (*powers[power])); + APowerup *item = static_cast<APowerup*>(players[i].mo->GiveInventoryType (static_cast<PClassActor *>(*powers[power]))); if (item != NULL && power == 0 && arg1 == 1) { item->BlendColor = MakeSpecialColormap(INVERSECOLORMAP); @@ -2611,7 +2611,7 @@ FUNC(LS_SetPlayerProperty) { // Take power if (power != 4) { - AInventory *item = players[i].mo->FindInventory (*powers[power]); + AInventory *item = players[i].mo->FindInventory (static_cast<PClassActor *>(*powers[power])); if (item != NULL) { item->Destroy (); diff --git a/src/p_local.h b/src/p_local.h index 1707db26e..89c8f07ea 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -131,7 +131,7 @@ void P_CheckFakeFloorTriggers (AActor *mo, fixed_t oldz, bool oldz_has_viewheigh // [RH] P_THINGS // #define MAX_SPAWNABLES (256) -extern const PClass *SpawnableThings[MAX_SPAWNABLES]; +extern PClassActor *SpawnableThings[MAX_SPAWNABLES]; bool P_Thing_Spawn (int tid, AActor *source, int type, angle_t angle, bool fog, int newtid); bool P_Thing_Projectile (int tid, AActor *source, int type, const char * type_name, angle_t angle, @@ -399,13 +399,13 @@ void P_FindFloorCeiling (AActor *actor, bool onlymidtex = false); bool P_ChangeSector (sector_t* sector, int crunch, int amt, int floorOrCeil, bool isreset); fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor **pLineTarget = NULL, fixed_t vrange=0, bool forcenosmart=false, bool check3d = false, bool checknonshootable = false, AActor *target=NULL); -AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, const PClass *pufftype, bool ismelee = false); +AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, PClassActor *pufftype, bool ismelee = false); AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype, bool ismelee = false); void P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *target, angle_t angle, int pitch); void P_TraceBleed (int damage, AActor *target, angle_t angle, int pitch); void P_TraceBleed (int damage, AActor *target, AActor *missile); // missile version void P_TraceBleed (int damage, AActor *target); // random direction version -void P_RailAttack (AActor *source, int damage, int offset, int color1 = 0, int color2 = 0, float maxdiff = 0, bool silent = false, const PClass *puff = NULL, bool pierce = true); // [RH] Shoot a railgun +void P_RailAttack (AActor *source, int damage, int offset, int color1 = 0, int color2 = 0, float maxdiff = 0, bool silent = false, PClassActor *puff = NULL, bool pierce = true); // [RH] Shoot a railgun bool P_HitFloor (AActor *thing); bool P_HitWater (AActor *thing, sector_t *sec, fixed_t splashx = FIXED_MIN, fixed_t splashy = FIXED_MIN, fixed_t splashz=FIXED_MIN, bool checkabove = false, bool alert = true); void P_CheckSplash(AActor *self, fixed_t distance); diff --git a/src/p_map.cpp b/src/p_map.cpp index e3c7de323..0642ee440 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -3293,7 +3293,7 @@ static bool CheckForSpectral (FTraceResults &res) //========================================================================== AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, - int pitch, int damage, FName damageType, const PClass *pufftype, bool ismeleeattack) + int pitch, int damage, FName damageType, PClassActor *pufftype, bool ismeleeattack) { fixed_t vx, vy, vz, shootz; FTraceResults trace; @@ -3326,7 +3326,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, (t1->player->ReadyWeapon->flags2 & MF2_THRUGHOST)); // We need to check the defaults of the replacement here - AActor *puffDefaults = GetDefaultByType(pufftype->ActorInfo->GetReplacement()->Class); + AActor *puffDefaults = GetDefaultByType(pufftype->GetReplacement()); // if the puff uses a non-standard damage type this will override default and melee damage type. // All other explicitly passed damage types (currenty only MDK) will be preserved. @@ -3506,7 +3506,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype, bool ismeleeattack) { - const PClass * type = PClass::FindClass(pufftype); + PClassActor *type = PClass::FindActor(pufftype); if (type == NULL) { Printf("Attempt to spawn unknown actor type '%s'\n", pufftype.GetChars()); @@ -3731,7 +3731,7 @@ static bool ProcessNoPierceRailHit (FTraceResults &res) // //========================================================================== -void P_RailAttack (AActor *source, int damage, int offset, int color1, int color2, float maxdiff, bool silent, const PClass *puffclass, bool pierce) +void P_RailAttack (AActor *source, int damage, int offset, int color1, int color2, float maxdiff, bool silent, PClassActor *puffclass, bool pierce) { fixed_t vx, vy, vz; angle_t angle, pitch; @@ -3740,7 +3740,10 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color FTraceResults trace; fixed_t shootz; - if (puffclass == NULL) puffclass = PClass::FindClass(NAME_BulletPuff); + if (puffclass == NULL) + { + puffclass = PClass::FindActor(NAME_BulletPuff); + } pitch = (angle_t)(-source->pitch) >> ANGLETOFINESHIFT; angle = source->angle >> ANGLETOFINESHIFT; @@ -3774,8 +3777,8 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color int flags; - AActor *puffDefaults = puffclass == NULL? - NULL : GetDefaultByType (puffclass->ActorInfo->GetReplacement()->Class); + AActor *puffDefaults = puffclass == NULL ? + NULL : GetDefaultByType (puffclass->GetReplacement()); if (puffDefaults != NULL && puffDefaults->flags6 & MF6_NOTRIGGER) flags = 0; else flags = TRACE_PCross|TRACE_Impact; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 4db035941..e3b0dbba8 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -820,13 +820,14 @@ AInventory *AActor::DropInventory (AInventory *item) // //============================================================================ -AInventory *AActor::FindInventory (const PClass *type) +AInventory *AActor::FindInventory (PClassActor *type) { AInventory *item; - if (type == NULL) return NULL; - - assert (type->ActorInfo != NULL); + if (type == NULL) + { + return NULL; + } for (item = Inventory; item != NULL; item = item->Inventory) { if (item->GetClass() == type) @@ -839,7 +840,7 @@ AInventory *AActor::FindInventory (const PClass *type) AInventory *AActor::FindInventory (FName type) { - return FindInventory(PClass::FindClass(type)); + return FindInventory(PClass::FindActor(type)); } //============================================================================ @@ -1080,11 +1081,11 @@ bool AActor::Grind(bool items) A_BossDeath(this); } - const PClass *i = PClass::FindClass("RealGibs"); + PClassActor *i = PClass::FindActor("RealGibs"); if (i != NULL) { - i = i->ActorInfo->GetReplacement()->Class; + i = i->GetReplacement(); const AActor *defaults = GetDefaultByType (i); if (defaults->SpawnState == NULL || @@ -3505,25 +3506,21 @@ bool AActor::UpdateWaterLevel (fixed_t oldz, bool dosplash) // //========================================================================== -AActor *AActor::StaticSpawn (const PClass *type, fixed_t ix, fixed_t iy, fixed_t iz, replace_t allowreplacement, bool SpawningMapThing) +AActor *AActor::StaticSpawn (PClassActor *type, fixed_t ix, fixed_t iy, fixed_t iz, replace_t allowreplacement, bool SpawningMapThing) { if (type == NULL) { I_Error ("Tried to spawn a class-less actor\n"); } - if (type->ActorInfo == NULL) - { - I_Error ("%s is not an actor\n", type->TypeName.GetChars()); - } - if (allowreplacement) - type = type->ActorInfo->GetReplacement()->Class; - + { + type = type->GetReplacement(); + } AActor *actor; - actor = static_cast<AActor *>(const_cast<PClass *>(type)->CreateNew ()); + actor = static_cast<AActor *>(const_cast<PClassActor *>(type)->CreateNew ()); actor->x = actor->PrevX = ix; actor->y = actor->PrevY = iy; @@ -3693,7 +3690,11 @@ AActor *Spawn (FName classname, fixed_t x, fixed_t y, fixed_t z, replace_t allow { I_Error("Attempt to spawn actor of unknown type '%s'\n", classname.GetChars()); } - return AActor::StaticSpawn (cls, x, y, z, allowreplacement); + if (!cls->IsKindOf(RUNTIME_CLASS(PClassActor))) + { + I_Error("Attempt to spawn non-actor of type '%s'\n", classname.GetChars()); + } + return AActor::StaticSpawn (const_cast<PClassActor *>(static_cast<const PClassActor *>(cls)), x, y, z, allowreplacement); } void AActor::LevelSpawned () @@ -4134,7 +4135,7 @@ APlayerPawn *P_SpawnPlayer (FMapThing *mthing, bool tempplayer) // [RH] position is used to weed out unwanted start spots AActor *P_SpawnMapThing (FMapThing *mthing, int position) { - const PClass *i; + PClassActor *i; int mask; AActor *mobj; fixed_t x, y, z; @@ -4318,7 +4319,8 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) Printf ("Unknown type %i at (%i, %i)\n", mthing->type, mthing->x>>FRACBITS, mthing->y>>FRACBITS); - i = PClass::FindClass("Unknown"); + i = PClass::FindActor("Unknown"); + assert(i->IsKindOf(RUNTIME_CLASS(PClassActor))); } // [RH] If the thing's corresponding sprite has no frames, also map // it to the unknown thing. @@ -4326,7 +4328,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) { // Handle decorate replacements explicitly here // to check for missing frames in the replacement object. - i = i->ActorInfo->GetReplacement()->Class; + i = i->GetReplacement(); const AActor *defaults = GetDefaultByType (i); if (defaults->SpawnState == NULL || @@ -4334,7 +4336,8 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) { Printf ("%s at (%i, %i) has no frames\n", i->TypeName.GetChars(), mthing->x>>FRACBITS, mthing->y>>FRACBITS); - i = PClass::FindClass("Unknown"); + i = PClass::FindActor("Unknown"); + assert(i->IsKindOf(RUNTIME_CLASS(PClassActor))); } } diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 37fb2f651..b389c51e4 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -769,7 +769,7 @@ angle_t P_BulletSlope (AActor *mo, AActor **pLineTarget) // // P_GunShot // -void P_GunShot (AActor *mo, bool accurate, const PClass *pufftype, angle_t pitch) +void P_GunShot (AActor *mo, bool accurate, PClassActor *pufftype, angle_t pitch) { angle_t angle; int damage; diff --git a/src/p_pspr.h b/src/p_pspr.h index 90a57b555..bd3ae6cad 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -87,12 +87,12 @@ void P_FireWeapon (player_t *player); void P_DropWeapon (player_t *player); void P_BobWeapon (player_t *player, pspdef_t *psp, fixed_t *x, fixed_t *y); angle_t P_BulletSlope (AActor *mo, AActor **pLineTarget = NULL); -void P_GunShot (AActor *mo, bool accurate, const PClass *pufftype, angle_t pitch); +void P_GunShot (AActor *mo, bool accurate, PClassActor *pufftype, angle_t pitch); -void DoReadyWeapon(AActor * self); -void DoReadyWeaponToBob(AActor * self); -void DoReadyWeaponToFire(AActor * self, bool primary = true, bool secondary = true); -void DoReadyWeaponToSwitch(AActor * self); +void DoReadyWeapon(AActor *self); +void DoReadyWeaponToBob(AActor *self); +void DoReadyWeaponToFire(AActor *self, bool primary = true, bool secondary = true); +void DoReadyWeaponToSwitch(AActor *self); DECLARE_ACTION(A_Raise) void A_ReFire(AActor *self, FState *state = NULL); diff --git a/src/p_states.cpp b/src/p_states.cpp index 9d5be4a5e..cd5543a74 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -60,7 +60,7 @@ FArchive &operator<< (FArchive &arc, FState *&state) { - const PClass *info; + const PClassActor *info; if (arc.IsStoring ()) { @@ -76,7 +76,7 @@ FArchive &operator<< (FArchive &arc, FState *&state) if (info != NULL) { arc.UserWriteClass (info); - arc.WriteCount ((DWORD)(state - info->ActorInfo->OwnedStates)); + arc.WriteCount ((DWORD)(state - info->OwnedStates)); } else { @@ -94,22 +94,18 @@ FArchive &operator<< (FArchive &arc, FState *&state) } else { - const PClass *info; + const PClassActor *info; DWORD ofs; - arc.UserReadClass (info); + arc.UserReadClass<PClassActor>(info); ofs = arc.ReadCount (); if (ofs == NULL_STATE_INDEX && info == RUNTIME_CLASS(AActor)) { state = NULL; } - else if (info->ActorInfo != NULL) - { - state = info->ActorInfo->OwnedStates + ofs; - } else { - state = NULL; + state = info->OwnedStates + ofs; } } return arc; @@ -121,15 +117,15 @@ FArchive &operator<< (FArchive &arc, FState *&state) // //========================================================================== -const PClass *FState::StaticFindStateOwner (const FState *state) +const PClassActor *FState::StaticFindStateOwner (const FState *state) { for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i) { - FActorInfo *info = PClass::m_RuntimeActors[i]->ActorInfo; + PClassActor *info = PClass::m_RuntimeActors[i]; if (state >= info->OwnedStates && state < info->OwnedStates + info->NumOwnedStates) { - return info->Class; + return info; } } @@ -143,16 +139,16 @@ const PClass *FState::StaticFindStateOwner (const FState *state) // //========================================================================== -const PClass *FState::StaticFindStateOwner (const FState *state, const FActorInfo *info) +const PClassActor *FState::StaticFindStateOwner (const FState *state, const PClassActor *info) { while (info != NULL) { if (state >= info->OwnedStates && state < info->OwnedStates + info->NumOwnedStates) { - return info->Class; + return info; } - info = info->Class->ParentClass->ActorInfo; + info = dyn_cast<PClassActor>(info->ParentClass); } return NULL; } @@ -165,18 +161,18 @@ const PClass *FState::StaticFindStateOwner (const FState *state, const FActorInf FStateLabel *FStateLabels::FindLabel (FName label) { - return const_cast<FStateLabel *>(BinarySearch<FStateLabel, FName> (Labels, NumLabels, &FStateLabel::Label, label)); + return const_cast<FStateLabel *>(BinarySearch<FStateLabel, FName>(Labels, NumLabels, &FStateLabel::Label, label)); } void FStateLabels::Destroy () { - for(int i=0; i<NumLabels;i++) + for(int i = 0; i < NumLabels; i++) { if (Labels[i].Children != NULL) { Labels[i].Children->Destroy(); - free (Labels[i].Children); // These are malloc'd, not new'd! - Labels[i].Children=NULL; + free(Labels[i].Children); // These are malloc'd, not new'd! + Labels[i].Children = NULL; } } } @@ -192,16 +188,19 @@ void FStateLabels::Destroy () bool AActor::HasSpecialDeathStates () const { - const FActorInfo *info = GetClass()->ActorInfo; + const PClassActor *info = static_cast<PClassActor *>(GetClass()); if (info->StateList != NULL) { FStateLabel *slabel = info->StateList->FindLabel (NAME_Death); if (slabel != NULL && slabel->Children != NULL) { - for(int i=0;i<slabel->Children->NumLabels;i++) + for(int i = 0; i < slabel->Children->NumLabels; i++) { - if (slabel->Children->Labels[i].State != NULL) return true; + if (slabel->Children->Labels[i].State != NULL) + { + return true; + } } } } @@ -218,10 +217,10 @@ TArray<FName> &MakeStateNameList(const char * fname) { static TArray<FName> namelist(3); FName firstpart, secondpart; - char * c; + char *c; // Handle the old names for the existing death states - char * name = copystring(fname); + char *name = copystring(fname); firstpart = strtok(name, "."); switch (firstpart) { @@ -245,14 +244,17 @@ TArray<FName> &MakeStateNameList(const char * fname) namelist.Clear(); namelist.Push(firstpart); - if (secondpart!=NAME_None) namelist.Push(secondpart); + if (secondpart != NAME_None) + { + namelist.Push(secondpart); + } - while ((c = strtok(NULL, "."))!=NULL) + while ((c = strtok(NULL, ".")) != NULL) { FName cc = c; namelist.Push(cc); } - delete [] name; + delete[] name; return namelist; } @@ -271,7 +273,7 @@ TArray<FName> &MakeStateNameList(const char * fname) // has names, ignore it. If the argument list still has names, remember it. // //=========================================================================== -FState *FActorInfo::FindState (int numnames, FName *names, bool exact) const +FState *PClassActor::FindState(int numnames, FName *names, bool exact) const { FStateLabels *labels = StateList; FState *best = NULL; @@ -286,7 +288,7 @@ FState *FActorInfo::FindState (int numnames, FName *names, bool exact) const while (labels != NULL && count < numnames) { label = *names++; - slabel = labels->FindLabel (label); + slabel = labels->FindLabel(label); if (slabel != NULL) { @@ -299,7 +301,10 @@ FState *FActorInfo::FindState (int numnames, FName *names, bool exact) const break; } } - if (count < numnames && exact) return NULL; + if (count < numnames && exact) + { + return NULL; + } } return best; } @@ -310,7 +315,7 @@ FState *FActorInfo::FindState (int numnames, FName *names, bool exact) const // //========================================================================== -FState *FActorInfo::FindStateByString(const char *name, bool exact) +FState *PClassActor::FindStateByString(const char *name, bool exact) { TArray<FName> &namelist = MakeStateNameList(name); return FindState(namelist.Size(), &namelist[0], exact); @@ -329,7 +334,10 @@ FStateDefine *FStateDefinitions::FindStateLabelInList(TArray<FStateDefine> & lis { for(unsigned i = 0; i<list.Size(); i++) { - if (list[i].Label == name) return &list[i]; + if (list[i].Label == name) + { + return &list[i]; + } } if (create) { @@ -349,14 +357,14 @@ FStateDefine *FStateDefinitions::FindStateLabelInList(TArray<FStateDefine> & lis // //========================================================================== -FStateDefine * FStateDefinitions::FindStateAddress(const char *name) +FStateDefine *FStateDefinitions::FindStateAddress(const char *name) { - FStateDefine * statedef=NULL; + FStateDefine *statedef=NULL; TArray<FName> &namelist = MakeStateNameList(name); - TArray<FStateDefine> * statelist = &StateLabels; - for(unsigned i=0;i<namelist.Size();i++) + TArray<FStateDefine> *statelist = &StateLabels; + for(unsigned i = 0; i < namelist.Size(); i++) { statedef = FindStateLabelInList(*statelist, namelist[i], true); statelist = &statedef->Children; @@ -370,7 +378,7 @@ FStateDefine * FStateDefinitions::FindStateAddress(const char *name) // //========================================================================== -void FStateDefinitions::SetStateLabel (const char *statename, FState *state, BYTE defflags) +void FStateDefinitions::SetStateLabel(const char *statename, FState *state, BYTE defflags) { FStateDefine *std = FindStateAddress(statename); std->State = state; @@ -383,7 +391,7 @@ void FStateDefinitions::SetStateLabel (const char *statename, FState *state, BYT // //========================================================================== -void FStateDefinitions::AddStateLabel (const char *statename) +void FStateDefinitions::AddStateLabel(const char *statename) { intptr_t index = StateArray.Size(); FStateDefine *std = FindStateAddress(statename); @@ -400,20 +408,23 @@ void FStateDefinitions::AddStateLabel (const char *statename) // //========================================================================== -FState * FStateDefinitions::FindState(const char * name) +FState *FStateDefinitions::FindState(const char * name) { - FStateDefine * statedef=NULL; + FStateDefine *statedef = NULL; TArray<FName> &namelist = MakeStateNameList(name); - TArray<FStateDefine> * statelist = &StateLabels; - for(unsigned i=0;i<namelist.Size();i++) + TArray<FStateDefine> *statelist = &StateLabels; + for(unsigned i = 0; i < namelist.Size(); i++) { statedef = FindStateLabelInList(*statelist, namelist[i], false); - if (statedef == NULL) return NULL; + if (statedef == NULL) + { + return NULL; + } statelist = &statedef->Children; } - return statedef? statedef->State : NULL; + return statedef ? statedef->State : NULL; } //========================================================================== @@ -422,17 +433,17 @@ FState * FStateDefinitions::FindState(const char * name) // //========================================================================== -static int STACK_ARGS labelcmp(const void * a, const void * b) +static int STACK_ARGS labelcmp(const void *a, const void *b) { - FStateLabel * A = (FStateLabel *)a; - FStateLabel * B = (FStateLabel *)b; + FStateLabel *A = (FStateLabel *)a; + FStateLabel *B = (FStateLabel *)b; return ((int)A->Label - (int)B->Label); } -FStateLabels * FStateDefinitions::CreateStateLabelList(TArray<FStateDefine> & statelist) +FStateLabels *FStateDefinitions::CreateStateLabelList(TArray<FStateDefine> & statelist) { // First delete all empty labels from the list - for (int i=statelist.Size()-1;i>=0;i--) + for (int i = statelist.Size() - 1; i >= 0; i--) { if (statelist[i].Label == NAME_None || (statelist[i].State == NULL && statelist[i].Children.Size() == 0)) { @@ -440,11 +451,13 @@ FStateLabels * FStateDefinitions::CreateStateLabelList(TArray<FStateDefine> & st } } - int count=statelist.Size(); + int count = statelist.Size(); - if (count == 0) return NULL; - - FStateLabels * list = (FStateLabels*)M_Malloc(sizeof(FStateLabels)+(count-1)*sizeof(FStateLabel)); + if (count == 0) + { + return NULL; + } + FStateLabels *list = (FStateLabels*)M_Malloc(sizeof(FStateLabels)+(count-1)*sizeof(FStateLabel)); list->NumLabels = count; for (int i=0;i<count;i++) @@ -465,7 +478,7 @@ FStateLabels * FStateDefinitions::CreateStateLabelList(TArray<FStateDefine> & st // //=========================================================================== -void FStateDefinitions::InstallStates(FActorInfo *info, AActor *defaults) +void FStateDefinitions::InstallStates(PClassActor *info, AActor *defaults) { // First ensure we have a valid spawn state. FState *state = FindState("Spawn"); @@ -504,7 +517,7 @@ void FStateDefinitions::InstallStates(FActorInfo *info, AActor *defaults) void FStateDefinitions::MakeStateList(const FStateLabels *list, TArray<FStateDefine> &dest) { dest.Clear(); - if (list != NULL) for(int i=0;i<list->NumLabels;i++) + if (list != NULL) for (int i = 0; i < list->NumLabels; i++) { FStateDefine def; @@ -519,15 +532,15 @@ void FStateDefinitions::MakeStateList(const FStateLabels *list, TArray<FStateDef } } -void FStateDefinitions::MakeStateDefines(const PClass *cls) +void FStateDefinitions::MakeStateDefines(const PClassActor *cls) { StateArray.Clear(); laststate = NULL; lastlabel = -1; - if (cls != NULL && cls->ActorInfo != NULL && cls->ActorInfo->StateList != NULL) + if (cls != NULL && cls->StateList != NULL) { - MakeStateList(cls->ActorInfo->StateList, StateLabels); + MakeStateList(cls->StateList, StateLabels); } else { @@ -545,7 +558,7 @@ void FStateDefinitions::MakeStateDefines(const PClass *cls) void FStateDefinitions::AddStateDefines(const FStateLabels *list) { - if (list != NULL) for(int i=0;i<list->NumLabels;i++) + if (list != NULL) for(int i = 0; i < list->NumLabels; i++) { if (list->Labels[i].Children == NULL) { @@ -613,9 +626,9 @@ void FStateDefinitions::RetargetStates (intptr_t count, const char *target) // //========================================================================== -FState *FStateDefinitions::ResolveGotoLabel (AActor *actor, const PClass *mytype, char *name) +FState *FStateDefinitions::ResolveGotoLabel (AActor *actor, PClassActor *mytype, char *name) { - const PClass *type=mytype; + PClassActor *type = mytype; FState *state; char *namestart = name; char *label, *offset, *pt; @@ -632,13 +645,13 @@ FState *FStateDefinitions::ResolveGotoLabel (AActor *actor, const PClass *mytype // superclass, or it may be the name of any class that this one derives from. if (stricmp (classname, "Super") == 0) { - type = type->ParentClass; - actor = GetDefaultByType (type); + type = dyn_cast<PClassActor>(type->ParentClass); + actor = GetDefaultByType(type); } else { // first check whether a state of the desired name exists - const PClass *stype = PClass::FindClass (classname); + PClass *stype = PClass::FindClass (classname); if (stype == NULL) { I_Error ("%s is an unknown class.", classname); @@ -654,7 +667,7 @@ FState *FStateDefinitions::ResolveGotoLabel (AActor *actor, const PClass *mytype } if (type != stype) { - type = stype; + type = static_cast<PClassActor *>(stype); actor = GetDefaultByType (type); } } @@ -670,8 +683,14 @@ FState *FStateDefinitions::ResolveGotoLabel (AActor *actor, const PClass *mytype v = offset ? strtol (offset, NULL, 0) : 0; // Get the state's address. - if (type==mytype) state = FindState (label); - else state = type->ActorInfo->FindStateByString(label, true); + if (type == mytype) + { + state = FindState (label); + } + else + { + state = type->FindStateByString(label, true); + } if (state != NULL) { @@ -693,17 +712,20 @@ FState *FStateDefinitions::ResolveGotoLabel (AActor *actor, const PClass *mytype // //========================================================================== -void FStateDefinitions::FixStatePointers (FActorInfo *actor, TArray<FStateDefine> & list) +void FStateDefinitions::FixStatePointers (PClassActor *actor, TArray<FStateDefine> & list) { - for(unsigned i=0;i<list.Size(); i++) + for (unsigned i = 0; i < list.Size(); i++) { if (list[i].DefineFlags == SDF_INDEX) { - size_t v=(size_t)list[i].State; + size_t v = (size_t)list[i].State; list[i].State = actor->OwnedStates + v - 1; list[i].DefineFlags = SDF_STATE; } - if (list[i].Children.Size() > 0) FixStatePointers(actor, list[i].Children); + if (list[i].Children.Size() > 0) + { + FixStatePointers(actor, list[i].Children); + } } } @@ -715,13 +737,13 @@ void FStateDefinitions::FixStatePointers (FActorInfo *actor, TArray<FStateDefine // //========================================================================== -void FStateDefinitions::ResolveGotoLabels (FActorInfo *actor, AActor *defaults, TArray<FStateDefine> & list) +void FStateDefinitions::ResolveGotoLabels (PClassActor *actor, AActor *defaults, TArray<FStateDefine> & list) { - for(unsigned i=0;i<list.Size(); i++) + for (unsigned i = 0; i < list.Size(); i++) { if (list[i].State != NULL && list[i].DefineFlags == SDF_LABEL) { // It's not a valid state, so it must be a label string. Resolve it. - list[i].State = ResolveGotoLabel (defaults, actor->Class, (char *)list[i].State); + list[i].State = ResolveGotoLabel (defaults, actor, (char *)list[i].State); list[i].DefineFlags = SDF_STATE; } if (list[i].Children.Size() > 0) ResolveGotoLabels(actor, defaults, list[i].Children); @@ -858,9 +880,9 @@ int FStateDefinitions::AddStates(FState *state, const char *framechars) // //========================================================================== -int FStateDefinitions::FinishStates (FActorInfo *actor, AActor *defaults) +int FStateDefinitions::FinishStates(PClassActor *actor, AActor *defaults) { - static int c=0; + static int c = 0; int count = StateArray.Size(); if (count > 0) @@ -882,11 +904,11 @@ int FStateDefinitions::FinishStates (FActorInfo *actor, AActor *defaults) // resolve labels and jumps switch(realstates[i].DefineFlags) { - case SDF_STOP: // stop + case SDF_STOP: // stop realstates[i].NextState = NULL; break; - case SDF_WAIT: // wait + case SDF_WAIT: // wait realstates[i].NextState = &realstates[i]; break; @@ -899,14 +921,14 @@ int FStateDefinitions::FinishStates (FActorInfo *actor, AActor *defaults) break; case SDF_LABEL: - realstates[i].NextState = ResolveGotoLabel (defaults, actor->Class, (char *)realstates[i].NextState); + realstates[i].NextState = ResolveGotoLabel(defaults, actor, (char *)realstates[i].NextState); break; } } } // Fix state pointers that are gotos - ResolveGotoLabels (actor, defaults, StateLabels); + ResolveGotoLabels(actor, defaults, StateLabels); return count; } @@ -924,7 +946,7 @@ void DumpStateHelper(FStateLabels *StateList, const FString &prefix) { if (StateList->Labels[i].State != NULL) { - const PClass *owner = FState::StaticFindStateOwner(StateList->Labels[i].State); + const PClassActor *owner = FState::StaticFindStateOwner(StateList->Labels[i].State); if (owner == NULL) { Printf(PRINT_LOG, "%s%s: invalid\n", prefix.GetChars(), StateList->Labels[i].Label.GetChars()); @@ -932,7 +954,7 @@ void DumpStateHelper(FStateLabels *StateList, const FString &prefix) else { Printf(PRINT_LOG, "%s%s: %s.%d\n", prefix.GetChars(), StateList->Labels[i].Label.GetChars(), - owner->TypeName.GetChars(), int(StateList->Labels[i].State - owner->ActorInfo->OwnedStates)); + owner->TypeName.GetChars(), int(StateList->Labels[i].State - owner->OwnedStates)); } } if (StateList->Labels[i].Children != NULL) @@ -946,8 +968,8 @@ CCMD(dumpstates) { for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i) { - FActorInfo *info = PClass::m_RuntimeActors[i]->ActorInfo; - Printf(PRINT_LOG, "State labels for %s\n", info->Class->TypeName.GetChars()); + PClassActor *info = PClass::m_RuntimeActors[i]; + Printf(PRINT_LOG, "State labels for %s\n", info->TypeName.GetChars()); DumpStateHelper(info->StateList, ""); Printf(PRINT_LOG, "----------------------------\n"); } diff --git a/src/p_things.cpp b/src/p_things.cpp index cd1540f4f..9b711f101 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -47,14 +47,14 @@ #include "g_level.h" // List of spawnable things for the Thing_Spawn and Thing_Projectile specials. -const PClass *SpawnableThings[MAX_SPAWNABLES]; +PClassActor *SpawnableThings[MAX_SPAWNABLES]; static FRandom pr_leadtarget ("LeadTarget"); bool P_Thing_Spawn (int tid, AActor *source, int type, angle_t angle, bool fog, int newtid) { int rtn = 0; - const PClass *kind; + PClassActor *kind; AActor *spot, *mobj; FActorIterator iterator (tid); @@ -65,9 +65,9 @@ bool P_Thing_Spawn (int tid, AActor *source, int type, angle_t angle, bool fog, return false; // Handle decorate replacements. - kind = kind->ActorInfo->GetReplacement()->Class; + kind = kind->GetReplacement(); - if ((GetDefaultByType (kind)->flags3 & MF3_ISMONSTER) && + if ((GetDefaultByType(kind)->flags3 & MF3_ISMONSTER) && ((dmflags & DF_NO_MONSTERS) || (level.flags2 & LEVEL2_NOMONSTERS))) return false; @@ -178,7 +178,7 @@ bool P_Thing_Projectile (int tid, AActor *source, int type, const char *type_nam bool leadTarget) { int rtn = 0; - const PClass *kind; + PClassActor *kind; AActor *spot, *mobj, *targ = forcedest; FActorIterator iterator (tid); double fspeed = speed; @@ -194,15 +194,15 @@ bool P_Thing_Projectile (int tid, AActor *source, int type, const char *type_nam } else { - if ((kind = PClass::FindClass(type_name)) == NULL || kind->ActorInfo == NULL) + if ((kind = PClass::FindActor(type_name)) == NULL) return false; } // Handle decorate replacements. - kind = kind->ActorInfo->GetReplacement()->Class; + kind = kind->GetReplacement(); - defflags3 = GetDefaultByType (kind)->flags3; + defflags3 = GetDefaultByType(kind)->flags3; if ((defflags3 & MF3_ISMONSTER) && ((dmflags & DF_NO_MONSTERS) || (level.flags2 & LEVEL2_NOMONSTERS))) return false; diff --git a/src/p_user.cpp b/src/p_user.cpp index fe1aab08c..77cd52fb7 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1053,7 +1053,7 @@ void APlayerPawn::GiveDefaultInventory () while (di) { - const PClass *ti = PClass::FindClass (di->Name); + PClassActor *ti = PClass::FindActor (di->Name); if (ti) { AInventory *item = FindInventory (ti); @@ -1104,7 +1104,7 @@ void APlayerPawn::MorphPlayerThink () void APlayerPawn::ActivateMorphWeapon () { - const PClass *morphweapon = PClass::FindClass (MorphWeapon); + PClassActor *morphweapon = PClass::FindActor (MorphWeapon); player->PendingWeapon = WP_NOCHANGE; player->psprites[ps_weapon].sy = WEAPONTOP; @@ -1341,8 +1341,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SkullPop) // [GRB] Parameterized version if (spawntype == NULL || !spawntype->IsDescendantOf(RUNTIME_CLASS(APlayerChunk))) { - spawntype = PClass::FindClass("BloodySkull"); - if (spawntype == NULL) return 0; + spawntype = PClass::FindActor("BloodySkull"); + if (spawntype == NULL) + return 0; } self->flags &= ~MF_SOLID; diff --git a/src/thingdef/olddecorations.cpp b/src/thingdef/olddecorations.cpp index 5ab7a2674..44afb3351 100644 --- a/src/thingdef/olddecorations.cpp +++ b/src/thingdef/olddecorations.cpp @@ -103,7 +103,7 @@ IMPLEMENT_CLASS (AFakeInventory) static void ParseInsideDecoration (Baggage &bag, AActor *defaults, FExtraInfo &extra, EDefinitionType def, FScanner &sc, TArray<FState> &StateArray); -static void ParseSpriteFrames (FActorInfo *info, TArray<FState> &states, FScanner &sc); +static void ParseSpriteFrames (PClassActor *info, TArray<FState> &states, FScanner &sc); // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -146,24 +146,22 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) Baggage bag; TArray<FState> StateArray; FExtraInfo extra; - FActorInfo *info; - PClass *type; - PClass *parent; + PClassActor *type; + PClassActor *parent; FName typeName; - if (def == DEF_Pickup) parent = RUNTIME_CLASS(AFakeInventory); - else parent = RUNTIME_CLASS(AActor); + parent = (def == DEF_Pickup) ? RUNTIME_CLASS(AFakeInventory) : RUNTIME_CLASS(AActor); sc.MustGetString(); typeName = FName(sc.String); - type = parent->CreateDerivedClass (typeName, parent->Size); + type = static_cast<PClassActor *>(parent->CreateDerivedClass (typeName, parent->Size)); ResetBaggage(&bag, parent); - info = bag.Info = type->ActorInfo; + bag.Info = type; #ifdef _DEBUG bag.ClassName = type->TypeName; #endif - info->GameFilter = GAME_Any; + type->GameFilter = GAME_Any; sc.MustGetStringName("{"); memset (&extra, 0, sizeof(extra)); @@ -192,15 +190,15 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) // Make a copy of the final frozen frame for A_FreezeDeathChunks FState icecopy = StateArray[extra.IceDeathEnd-1]; StateArray.Push (icecopy); - info->NumOwnedStates += 1; + type->NumOwnedStates += 1; } - info->OwnedStates = new FState[info->NumOwnedStates]; - memcpy (info->OwnedStates, &StateArray[0], info->NumOwnedStates * sizeof(info->OwnedStates[0])); - if (info->NumOwnedStates == 1) + type->OwnedStates = new FState[type->NumOwnedStates]; + memcpy (type->OwnedStates, &StateArray[0], type->NumOwnedStates * sizeof(type->OwnedStates[0])); + if (type->NumOwnedStates == 1) { - info->OwnedStates->Tics = -1; - info->OwnedStates->Misc1 = 0; + type->OwnedStates->Tics = -1; + type->OwnedStates->Misc1 = 0; } else { @@ -209,55 +207,58 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) // Spawn states loop endlessly for (i = extra.SpawnStart; i < extra.SpawnEnd-1; ++i) { - info->OwnedStates[i].NextState = &info->OwnedStates[i+1]; + type->OwnedStates[i].NextState = &type->OwnedStates[i+1]; } - info->OwnedStates[i].NextState = &info->OwnedStates[extra.SpawnStart]; + type->OwnedStates[i].NextState = &type->OwnedStates[extra.SpawnStart]; // Death states are one-shot and freeze on the final state if (extra.DeathEnd != 0) { for (i = extra.DeathStart; i < extra.DeathEnd-1; ++i) { - info->OwnedStates[i].NextState = &info->OwnedStates[i+1]; + type->OwnedStates[i].NextState = &type->OwnedStates[i+1]; } if (extra.bDiesAway || def == DEF_Projectile) { - info->OwnedStates[i].NextState = NULL; + type->OwnedStates[i].NextState = NULL; } else { - info->OwnedStates[i].Tics = -1; - info->OwnedStates[i].Misc1 = 0; + type->OwnedStates[i].Tics = -1; + type->OwnedStates[i].Misc1 = 0; } if (def == DEF_Projectile) { if (extra.bExplosive) { - info->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_Explode")->Function); + type->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_Explode")->Function); } } else { // The first frame plays the death sound and // the second frame makes it nonsolid. - info->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_Scream")->Function); + type->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_Scream")->Function); if (extra.bSolidOnDeath) { } else if (extra.DeathStart + 1 < extra.DeathEnd) { - info->OwnedStates[extra.DeathStart+1].SetAction(FindGlobalActionFunction("A_NoBlocking")->Function); + type->OwnedStates[extra.DeathStart+1].SetAction(FindGlobalActionFunction("A_NoBlocking")->Function); } else { - info->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_ScreamAndUnblock")->Function); + type->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_ScreamAndUnblock")->Function); } - if (extra.DeathHeight == 0) extra.DeathHeight = ((AActor*)(type->Defaults))->height; - info->Class->Meta.SetMetaFixed (AMETA_DeathHeight, extra.DeathHeight); + if (extra.DeathHeight == 0) + { + extra.DeathHeight = ((AActor*)(type->Defaults))->height; + } + type->Meta.SetMetaFixed (AMETA_DeathHeight, extra.DeathHeight); } - bag.statedef.SetStateLabel("Death", &info->OwnedStates[extra.DeathStart]); + bag.statedef.SetStateLabel("Death", &type->OwnedStates[extra.DeathStart]); } // Burn states are the same as death states, except they can optionally terminate @@ -265,37 +266,37 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) { for (i = extra.FireDeathStart; i < extra.FireDeathEnd-1; ++i) { - info->OwnedStates[i].NextState = &info->OwnedStates[i+1]; + type->OwnedStates[i].NextState = &type->OwnedStates[i+1]; } if (extra.bBurnAway) { - info->OwnedStates[i].NextState = NULL; + type->OwnedStates[i].NextState = NULL; } else { - info->OwnedStates[i].Tics = -1; - info->OwnedStates[i].Misc1 = 0; + type->OwnedStates[i].Tics = -1; + type->OwnedStates[i].Misc1 = 0; } // The first frame plays the burn sound and // the second frame makes it nonsolid. - info->OwnedStates[extra.FireDeathStart].SetAction(FindGlobalActionFunction("A_ActiveSound")->Function); + type->OwnedStates[extra.FireDeathStart].SetAction(FindGlobalActionFunction("A_ActiveSound")->Function); if (extra.bSolidOnBurn) { } else if (extra.FireDeathStart + 1 < extra.FireDeathEnd) { - info->OwnedStates[extra.FireDeathStart+1].SetAction(FindGlobalActionFunction("A_NoBlocking")->Function); + type->OwnedStates[extra.FireDeathStart+1].SetAction(FindGlobalActionFunction("A_NoBlocking")->Function); } else { - info->OwnedStates[extra.FireDeathStart].SetAction(FindGlobalActionFunction("A_ActiveAndUnblock")->Function); + type->OwnedStates[extra.FireDeathStart].SetAction(FindGlobalActionFunction("A_ActiveAndUnblock")->Function); } if (extra.BurnHeight == 0) extra.BurnHeight = ((AActor*)(type->Defaults))->height; type->Meta.SetMetaFixed (AMETA_BurnHeight, extra.BurnHeight); - bag.statedef.SetStateLabel("Burn", &info->OwnedStates[extra.FireDeathStart]); + bag.statedef.SetStateLabel("Burn", &type->OwnedStates[extra.FireDeathStart]); } // Ice states are similar to burn and death, except their final frame enters @@ -304,23 +305,23 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) { for (i = extra.IceDeathStart; i < extra.IceDeathEnd-1; ++i) { - info->OwnedStates[i].NextState = &info->OwnedStates[i+1]; + type->OwnedStates[i].NextState = &type->OwnedStates[i+1]; } - info->OwnedStates[i].NextState = &info->OwnedStates[info->NumOwnedStates-1]; - info->OwnedStates[i].Tics = 5; - info->OwnedStates[i].Misc1 = 0; - info->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeath")->Function); + type->OwnedStates[i].NextState = &type->OwnedStates[type->NumOwnedStates-1]; + type->OwnedStates[i].Tics = 5; + type->OwnedStates[i].Misc1 = 0; + type->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeath")->Function); - i = info->NumOwnedStates - 1; - info->OwnedStates[i].NextState = &info->OwnedStates[i]; - info->OwnedStates[i].Tics = 1; - info->OwnedStates[i].Misc1 = 0; - info->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeathChunks")->Function); - bag.statedef.SetStateLabel("Ice", &info->OwnedStates[extra.IceDeathStart]); + i = type->NumOwnedStates - 1; + type->OwnedStates[i].NextState = &type->OwnedStates[i]; + type->OwnedStates[i].Tics = 1; + type->OwnedStates[i].Misc1 = 0; + type->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeathChunks")->Function); + bag.statedef.SetStateLabel("Ice", &type->OwnedStates[extra.IceDeathStart]); } else if (extra.bGenericIceDeath) { - bag.statedef.SetStateLabel("Ice", RUNTIME_CLASS(AActor)->ActorInfo->FindState(NAME_GenericFreezeDeath)); + bag.statedef.SetStateLabel("Ice", RUNTIME_CLASS(AActor)->FindState(NAME_GenericFreezeDeath)); } } if (def == DEF_BreakableDecoration) @@ -331,8 +332,8 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) { ((AActor *)(type->Defaults))->flags |= MF_DROPOFF|MF_MISSILE; } - bag.statedef.SetStateLabel("Spawn", &info->OwnedStates[extra.SpawnStart]); - bag.statedef.InstallStates (info, ((AActor *)(type->Defaults))); + bag.statedef.SetStateLabel("Spawn", &type->OwnedStates[extra.SpawnStart]); + bag.statedef.InstallStates (type, ((AActor *)(type->Defaults))); } //========================================================================== @@ -474,18 +475,18 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, else if (def == DEF_Projectile && sc.Compare ("ExplosionRadius")) { sc.MustGetNumber (); - bag.Info->Class->Meta.SetMetaInt(ACMETA_ExplosionRadius, sc.Number); + bag.Info->Meta.SetMetaInt(ACMETA_ExplosionRadius, sc.Number); extra.bExplosive = true; } else if (def == DEF_Projectile && sc.Compare ("ExplosionDamage")) { sc.MustGetNumber (); - bag.Info->Class->Meta.SetMetaInt(ACMETA_ExplosionDamage, sc.Number); + bag.Info->Meta.SetMetaInt(ACMETA_ExplosionDamage, sc.Number); extra.bExplosive = true; } else if (def == DEF_Projectile && sc.Compare ("DoNotHurtShooter")) { - bag.Info->Class->Meta.SetMetaInt(ACMETA_DontHurtShooter, true); + bag.Info->Meta.SetMetaInt(ACMETA_DontHurtShooter, true); } else if (def == DEF_Projectile && sc.Compare ("Damage")) { @@ -570,7 +571,7 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, else if (def == DEF_Pickup && sc.Compare ("PickupMessage")) { sc.MustGetString (); - bag.Info->Class->Meta.SetMetaString(AIMETA_PickupMessage, sc.String); + bag.Info->Meta.SetMetaString(AIMETA_PickupMessage, sc.String); } else if (def == DEF_Pickup && sc.Compare ("Respawns")) { @@ -641,7 +642,7 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, // "10:A, 15:B, 8:C, 6:B" //========================================================================== -static void ParseSpriteFrames (FActorInfo *info, TArray<FState> &states, FScanner &sc) +static void ParseSpriteFrames (PClassActor *info, TArray<FState> &states, FScanner &sc) { FState state; char *token = strtok (sc.String, ",\t\n\r"); diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index b22e558d3..00694457c 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -71,27 +71,26 @@ void InitThingdef(); void ParseDecorate (FScanner &sc); // STATIC FUNCTION PROTOTYPES -------------------------------------------- -const PClass *QuestItemClasses[31]; -PSymbolTable GlobalSymbols; +PClassActor *QuestItemClasses[31]; +PSymbolTable GlobalSymbols; //========================================================================== // // Starts a new actor definition // //========================================================================== -FActorInfo *CreateNewActor(const FScriptPosition &sc, FName typeName, FName parentName, bool native) +PClassActor *CreateNewActor(const FScriptPosition &sc, FName typeName, FName parentName, bool native) { - const PClass *replacee = NULL; - PClass *ti = NULL; - FActorInfo *info = NULL; + PClassActor *replacee = NULL; + PClassActor *ti = NULL; - PClass *parent = RUNTIME_CLASS(AActor); + PClassActor *parent = RUNTIME_CLASS(AActor); if (parentName != NAME_None) { - parent = const_cast<PClass *> (PClass::FindClass (parentName)); + parent = PClass::FindActor(parentName); - const PClass *p = parent; + PClassActor *p = parent; while (p != NULL) { if (p->TypeName == typeName) @@ -99,7 +98,7 @@ FActorInfo *CreateNewActor(const FScriptPosition &sc, FName typeName, FName pare sc.Message(MSG_ERROR, "'%s' inherits from a class with the same name", typeName.GetChars()); break; } - p = p->ParentClass; + p = dyn_cast<PClassActor>(p->ParentClass); } if (parent == NULL) @@ -112,19 +111,14 @@ FActorInfo *CreateNewActor(const FScriptPosition &sc, FName typeName, FName pare sc.Message(MSG_ERROR, "Parent type '%s' is not an actor in %s", parentName.GetChars(), typeName.GetChars()); parent = RUNTIME_CLASS(AActor); } - else if (parent->ActorInfo == NULL) - { - sc.Message(MSG_ERROR, "uninitialized parent type '%s' in %s", parentName.GetChars(), typeName.GetChars()); - parent = RUNTIME_CLASS(AActor); - } } if (native) { - ti = (PClass*)PClass::FindClass(typeName); + ti = PClass::FindActor(typeName); if (ti == NULL) { - sc.Message(MSG_ERROR, "Unknown native class '%s'", typeName.GetChars()); + sc.Message(MSG_ERROR, "Unknown native actor '%s'", typeName.GetChars()); goto create; } else if (ti != RUNTIME_CLASS(AActor) && ti->ParentClass->NativeClass() != parent->NativeClass()) @@ -133,36 +127,34 @@ FActorInfo *CreateNewActor(const FScriptPosition &sc, FName typeName, FName pare parent = RUNTIME_CLASS(AActor); goto create; } - else if (ti->ActorInfo != NULL) + else if (ti->Defaults != NULL) { sc.Message(MSG_ERROR, "Redefinition of internal class '%s'", typeName.GetChars()); goto create; } - ti->InitializeActorInfo(); - info = ti->ActorInfo; + ti->InitializeNativeDefaults(); } else { create: - ti = parent->CreateDerivedClass (typeName, parent->Size); - info = ti->ActorInfo; + ti = static_cast<PClassActor *>(parent->CreateDerivedClass (typeName, parent->Size)); } - if (parent->ActorInfo->DamageFactors != NULL) + if (parent->DamageFactors != NULL) { // copy damage factors from parent - info->DamageFactors = new DmgFactors; - *info->DamageFactors = *parent->ActorInfo->DamageFactors; + ti->DamageFactors = new DmgFactors; + *ti->DamageFactors = *parent->DamageFactors; } - if (parent->ActorInfo->PainChances != NULL) + if (parent->PainChances != NULL) { // copy pain chances from parent - info->PainChances = new PainChanceList; - *info->PainChances = *parent->ActorInfo->PainChances; + ti->PainChances = new PainChanceList; + *ti->PainChances = *parent->PainChances; } - info->Replacee = info->Replacement = NULL; - info->DoomEdNum = -1; - return info; + ti->Replacee = ti->Replacement = NULL; + ti->DoomEdNum = -1; + return ti; } //========================================================================== @@ -171,26 +163,22 @@ FActorInfo *CreateNewActor(const FScriptPosition &sc, FName typeName, FName pare // //========================================================================== -void SetReplacement(FActorInfo *info, FName replaceName) +void SetReplacement(PClassActor *info, FName replaceName) { // Check for "replaces" if (replaceName != NAME_None) { // Get actor name - const PClass *replacee = PClass::FindClass (replaceName); + PClassActor *replacee = PClass::FindActor(replaceName); if (replacee == NULL) { - I_Error ("Replaced type '%s' not found in %s", replaceName.GetChars(), info->Class->TypeName.GetChars()); - } - else if (replacee->ActorInfo == NULL) - { - I_Error ("Replaced type '%s' is not an actor in %s", replaceName.GetChars(), info->Class->TypeName.GetChars()); + I_Error ("Replaced type '%s' not found in %s", replaceName.GetChars(), info->TypeName.GetChars()); } if (replacee != NULL) { - replacee->ActorInfo->Replacement = info; - info->Replacee = replacee->ActorInfo; + replacee->Replacement = info; + info->Replacee = replacee; } } @@ -202,10 +190,9 @@ void SetReplacement(FActorInfo *info, FName replaceName) // //========================================================================== -void FinishActor(const FScriptPosition &sc, FActorInfo *info, Baggage &bag) +void FinishActor(const FScriptPosition &sc, PClassActor *info, Baggage &bag) { - PClass *ti = info->Class; - AActor *defaults = (AActor*)ti->Defaults; + AActor *defaults = (AActor*)info->Defaults; try { @@ -223,29 +210,28 @@ void FinishActor(const FScriptPosition &sc, FActorInfo *info, Baggage &bag) { if (bag.DropItemList == NULL) { - if (ti->Meta.GetMetaInt (ACMETA_DropItems) != 0) + if (info->Meta.GetMetaInt (ACMETA_DropItems) != 0) { - ti->Meta.SetMetaInt (ACMETA_DropItems, 0); + info->Meta.SetMetaInt (ACMETA_DropItems, 0); } } else { - ti->Meta.SetMetaInt (ACMETA_DropItems, - StoreDropItemChain(bag.DropItemList)); + info->Meta.SetMetaInt (ACMETA_DropItems, StoreDropItemChain(bag.DropItemList)); } } - if (ti->IsDescendantOf (RUNTIME_CLASS(AInventory))) + if (info->IsDescendantOf (RUNTIME_CLASS(AInventory))) { defaults->flags |= MF_SPECIAL; } // Weapons must be checked for all relevant states. They may crash the game otherwise. - if (ti->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (info->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { - FState * ready = ti->ActorInfo->FindState(NAME_Ready); - FState * select = ti->ActorInfo->FindState(NAME_Select); - FState * deselect = ti->ActorInfo->FindState(NAME_Deselect); - FState * fire = ti->ActorInfo->FindState(NAME_Fire); + FState *ready = info->FindState(NAME_Ready); + FState *select = info->FindState(NAME_Select); + FState *deselect = info->FindState(NAME_Deselect); + FState *fire = info->FindState(NAME_Fire); // Consider any weapon without any valid state abstract and don't output a warning // This is for creating base classes for weapon groups that only set up some properties. @@ -253,19 +239,19 @@ void FinishActor(const FScriptPosition &sc, FActorInfo *info, Baggage &bag) { if (!ready) { - sc.Message(MSG_ERROR, "Weapon %s doesn't define a ready state.\n", ti->TypeName.GetChars()); + sc.Message(MSG_ERROR, "Weapon %s doesn't define a ready state.\n", info->TypeName.GetChars()); } if (!select) { - sc.Message(MSG_ERROR, "Weapon %s doesn't define a select state.\n", ti->TypeName.GetChars()); + sc.Message(MSG_ERROR, "Weapon %s doesn't define a select state.\n", info->TypeName.GetChars()); } if (!deselect) { - sc.Message(MSG_ERROR, "Weapon %s doesn't define a deselect state.\n", ti->TypeName.GetChars()); + sc.Message(MSG_ERROR, "Weapon %s doesn't define a deselect state.\n", info->TypeName.GetChars()); } if (!fire) { - sc.Message(MSG_ERROR, "Weapon %s doesn't define a fire state.\n", ti->TypeName.GetChars()); + sc.Message(MSG_ERROR, "Weapon %s doesn't define a fire state.\n", info->TypeName.GetChars()); } } } @@ -295,7 +281,7 @@ static void FinishThingdef() } else { - FCompileContext ctx(tcall->ActorInfo->Class, true); + FCompileContext ctx(tcall->ActorClass, true); for (j = 0; j < tcall->Parameters.Size(); ++j) { tcall->Parameters[j]->Resolve(ctx); @@ -325,7 +311,7 @@ static void FinishThingdef() const char *marks = "======================================================="; char label[64]; int labellen = mysnprintf(label, countof(label), "Function %s.States[%d] (*%d)", - tcall->ActorInfo->Class->TypeName.GetChars(), + tcall->ActorClass->TypeName.GetChars(), tcall->FirstState, tcall->NumStates); fprintf(dump, "\n%.*s %s %.*s", MAX(3, 38 - labellen / 2), marks, label, MAX(3, 38 - labellen / 2), marks); fprintf(dump, "\nInteger regs: %-3d Float regs: %-3d Address regs: %-3d String regs: %-3d\nStack size: %d\n", @@ -337,7 +323,7 @@ static void FinishThingdef() } for (int k = 0; k < tcall->NumStates; ++k) { - tcall->ActorInfo->OwnedStates[tcall->FirstState + k].SetAction(func); + tcall->ActorClass->OwnedStates[tcall->FirstState + k].SetAction(func); } } fclose(dump); @@ -371,11 +357,11 @@ static void FinishThingdef() } // Since these are defined in DECORATE now the table has to be initialized here. - for(int i=0;i<31;i++) + for(int i = 0; i < 31; i++) { char fmt[20]; mysnprintf(fmt, countof(fmt), "QuestItem%d", i+1); - QuestItemClasses[i] = PClass::FindClass(fmt); + QuestItemClasses[i] = PClass::FindActor(fmt); } } diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index 4829cc306..31b1d1274 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -25,7 +25,7 @@ struct FFlagDef }; FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2); -void HandleDeprecatedFlags(AActor *defaults, FActorInfo *info, bool set, int index); +void HandleDeprecatedFlags(AActor *defaults, PClassActor *info, bool set, int index); const char *GetFlagName(int flagnum, int flagoffset); #define FLAG_NAME(flagnum, flagvar) GetFlagName(flagnum, myoffsetof(AActor, flagvar)) @@ -70,13 +70,13 @@ class FStateDefinitions static FStateDefine *FindStateLabelInList(TArray<FStateDefine> &list, FName name, bool create); static FStateLabels *CreateStateLabelList(TArray<FStateDefine> &statelist); static void MakeStateList(const FStateLabels *list, TArray<FStateDefine> &dest); - static void RetargetStatePointers (intptr_t count, const char *target, TArray<FStateDefine> & statelist); + static void RetargetStatePointers(intptr_t count, const char *target, TArray<FStateDefine> & statelist); FStateDefine *FindStateAddress(const char *name); FState *FindState(const char *name); - FState *ResolveGotoLabel (AActor *actor, const PClass *mytype, char *name); - static void FixStatePointers (FActorInfo *actor, TArray<FStateDefine> & list); - void ResolveGotoLabels (FActorInfo *actor, AActor *defaults, TArray<FStateDefine> & list); + FState *ResolveGotoLabel(AActor *actor, PClassActor *mytype, char *name); + static void FixStatePointers(PClassActor *actor, TArray<FStateDefine> & list); + void ResolveGotoLabels(PClassActor *actor, AActor *defaults, TArray<FStateDefine> & list); public: @@ -86,12 +86,12 @@ public: lastlabel = -1; } - void SetStateLabel (const char * statename, FState * state, BYTE defflags = SDF_STATE); - void AddStateLabel (const char * statename); - void InstallStates(FActorInfo *info, AActor *defaults); - int FinishStates (FActorInfo *actor, AActor *defaults); + void SetStateLabel(const char *statename, FState *state, BYTE defflags = SDF_STATE); + void AddStateLabel(const char *statename); + void InstallStates(PClassActor *info, AActor *defaults); + int FinishStates(PClassActor *actor, AActor *defaults); - void MakeStateDefines(const PClass *cls); + void MakeStateDefines(const PClassActor *cls); void AddStateDefines(const FStateLabels *list); void RetargetStates (intptr_t count, const char *target); @@ -111,9 +111,9 @@ public: struct FStateTempCall { - FStateTempCall() : ActorInfo(NULL), Function(NULL), FirstState(0), NumStates(0) {} + FStateTempCall() : ActorClass(NULL), Function(NULL), FirstState(0), NumStates(0) {} - FActorInfo *ActorInfo; + PClassActor *ActorClass; VMFunction *Function; TArray<FxExpression *> Parameters; int FirstState; @@ -124,7 +124,7 @@ extern TDeletingArray<FStateTempCall *> StateTempCalls; struct FStateExpression { FxExpression *expr; - const PClass *owner; + PClassActor *owner; bool constant; bool cloned; }; @@ -135,8 +135,8 @@ class FStateExpressions public: ~FStateExpressions(); - int Add(FxExpression *x, const PClass *o, bool c); - int Reserve(int num, const PClass *cls); + int Add(FxExpression *x, PClassActor *o, bool c); + int Reserve(int num, PClassActor *cls); void Set(int num, FxExpression *x, bool cloned = false); void Copy(int dest, int src, int cnt); int ResolveAll(); @@ -159,7 +159,7 @@ struct Baggage #ifdef _DEBUG FString ClassName; // This is here so that during debugging the class name can be seen #endif - FActorInfo *Info; + PClassActor *Info; bool DropItemSet; bool StateSet; int CurrentState; @@ -171,7 +171,7 @@ struct Baggage FScriptPosition ScriptPosition; }; -inline void ResetBaggage (Baggage *bag, const PClass *stateclass) +inline void ResetBaggage (Baggage *bag, PClassActor *stateclass) { bag->DropItemList = NULL; bag->DropItemSet = false; @@ -196,7 +196,7 @@ struct AFuncDesc AFuncDesc *FindFunction(const char * string); -void ParseStates(FScanner &sc, FActorInfo *actor, AActor *defaults, Baggage &bag); +void ParseStates(FScanner &sc, PClassActor *actor, AActor *defaults, Baggage &bag); PSymbolActionFunction *FindGlobalActionFunction(const char *name); @@ -206,12 +206,12 @@ PSymbolActionFunction *FindGlobalActionFunction(const char *name); // //========================================================================== -FActorInfo *CreateNewActor(const FScriptPosition &sc, FName typeName, FName parentName, bool native); -void SetReplacement(FActorInfo *info, FName replaceName); +PClassActor *CreateNewActor(const FScriptPosition &sc, FName typeName, FName parentName, bool native); +void SetReplacement(PClassActor *info, FName replaceName); void HandleActorFlag(FScanner &sc, Baggage &bag, const char *part1, const char *part2, int mod); -void FinishActor(const FScriptPosition &sc, FActorInfo *info, Baggage &bag); -FxExpression *ParseParameter(FScanner &sc, PClass *cls, char type, bool constant); +void FinishActor(const FScriptPosition &sc, PClassActor *info, Baggage &bag); +FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, char type, bool constant); enum @@ -282,7 +282,7 @@ union FPropParam const char *s; }; -typedef void (*PropHandler)(AActor *defaults, FActorInfo *info, Baggage &bag, FPropParam *params); +typedef void (*PropHandler)(AActor *defaults, PClassActor *info, Baggage &bag, FPropParam *params); enum ECategory { @@ -313,18 +313,18 @@ int MatchString (const char *in, const char **strings); #define DEFINE_PROPERTY_BASE(name, paramlist, clas, cat) \ - static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, FActorInfo *info, Baggage &bag, FPropParam *params); \ + static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, PClassActor *info, Baggage &bag, FPropParam *params); \ static FPropertyInfo Prop_##name##_##paramlist##_##clas = \ - { #name, #paramlist, &RUNTIME_CLASS(A##clas), (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \ + { #name, #paramlist, &RUNTIME_CLASS_CASTLESS(A##clas), (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \ MSVC_PSEG FPropertyInfo *infoptr_##name##_##paramlist##_##clas GCC_PSEG = &Prop_##name##_##paramlist##_##clas; \ - static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, FActorInfo *info, Baggage &bag, FPropParam *params) + static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, PClassActor *info, Baggage &bag, FPropParam *params) #define DEFINE_PREFIXED_PROPERTY_BASE(prefix, name, paramlist, clas, cat) \ - static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, FActorInfo *info, Baggage &bag, FPropParam *params); \ + static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, PClassActor *info, Baggage &bag, FPropParam *params); \ static FPropertyInfo Prop_##name##_##paramlist##_##clas = \ -{ #prefix"."#name, #paramlist, &RUNTIME_CLASS(A##clas), (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \ +{ #prefix"."#name, #paramlist, &RUNTIME_CLASS_CASTLESS(A##clas), (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \ MSVC_PSEG FPropertyInfo *infoptr_##name##_##paramlist##_##clas GCC_PSEG = &Prop_##name##_##paramlist##_##clas; \ - static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, FActorInfo *info, Baggage &bag, FPropParam *params) + static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, PClassActor *info, Baggage &bag, FPropParam *params) #define DEFINE_PROPERTY(name, paramlist, clas) DEFINE_PROPERTY_BASE(name, paramlist, clas, CAT_PROPERTY) @@ -352,11 +352,11 @@ int MatchString (const char *in, const char **strings); #define DEFINE_MEMBER_VARIABLE(name, cls) \ - static FVariableInfo GlobalDef__##name = { #name, myoffsetof(cls, name), &RUNTIME_CLASS(cls) }; \ + static FVariableInfo GlobalDef__##name = { #name, myoffsetof(cls, name), &RUNTIME_CLASS_CASTLESS(cls) }; \ MSVC_MSEG FVariableInfo *infoptr_GlobalDef__##name GCC_MSEG = &GlobalDef__##name; #define DEFINE_MEMBER_VARIABLE_ALIAS(name, alias, cls) \ - static FVariableInfo GlobalDef__##name = { #name, myoffsetof(cls, alias), &RUNTIME_CLASS(cls) }; \ + static FVariableInfo GlobalDef__##name = { #name, myoffsetof(cls, alias), &RUNTIME_CLASS_CASTLESS(cls) }; \ MSVC_MSEG FVariableInfo *infoptr_GlobalDef__##name GCC_MSEG = &GlobalDef__##name; diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 508467d16..a5d7ef98c 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -854,7 +854,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) PARAM_ANGLE (spread_z); PARAM_INT (numbullets); PARAM_INT (damageperbullet); - PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindClass(NAME_BulletPuff); } + PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindActor(NAME_BulletPuff); } PARAM_FIXED_OPT (range) { range = MISSILERANGE; } PARAM_BOOL_OPT (aimfacing) { aimfacing = false; } @@ -1037,7 +1037,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets) bangle = self->angle; if (pufftype == NULL) - pufftype = PClass::FindClass(NAME_BulletPuff); + pufftype = PClass::FindActor(NAME_BulletPuff); S_Sound(self, CHAN_WEAPON, weapon->AttackSound, 1, ATTN_NORM); @@ -1171,7 +1171,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) } if (pufftype == NULL) - pufftype = PClass::FindClass(NAME_BulletPuff); + pufftype = PClass::FindActor(NAME_BulletPuff); P_LineAttack (self, angle, range, pitch, damage, NAME_None, pufftype, true); @@ -1207,7 +1207,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack) PARAM_COLOR_OPT (color2) { color2 = 0; } PARAM_INT_OPT (flags) { flags = 0; } PARAM_FLOAT_OPT (maxdiff) { maxdiff = 0; } - PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindClass(NAME_BulletPuff); } + PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindActor(NAME_BulletPuff); } if (!self->player) return 0; @@ -1247,7 +1247,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) PARAM_INT_OPT (flags) { flags = 0; } PARAM_INT_OPT (aim) { aim = CRF_DONTAIM; } PARAM_FLOAT_OPT (maxdiff) { maxdiff = 0; } - PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindClass(NAME_BulletPuff); } + PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindActor(NAME_BulletPuff); } AActor *linetarget; @@ -1548,7 +1548,7 @@ static bool InitSpawnedItem(AActor *self, AActor *mo, int flags) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItem) { PARAM_ACTION_PROLOGUE; - PARAM_CLASS_OPT (missile, AActor) { missile = PClass::FindClass("Unknown"); } + PARAM_CLASS_OPT (missile, AActor) { missile = PClass::FindActor("Unknown"); } PARAM_FIXED_OPT (distance) { distance = 0; } PARAM_FIXED_OPT (zheight) { zheight = 0; } PARAM_BOOL_OPT (useammo) { useammo = true; } @@ -1985,9 +1985,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnDebris) { mo->Translation = self->Translation; } - if (mo && i < mo->GetClass()->ActorInfo->NumOwnedStates) + if (mo && i < mo->GetClass()->NumOwnedStates) { - mo->SetState (mo->GetClass()->ActorInfo->OwnedStates + i); + mo->SetState (mo->GetClass()->OwnedStates + i); mo->velz = FixedMul(mult_v, ((pr_spawndebris()&7)+5)*FRACUNIT); mo->velx = FixedMul(mult_h, pr_spawndebris.Random2()<<(FRACBITS-6)); mo->vely = FixedMul(mult_h, pr_spawndebris.Random2()<<(FRACBITS-6)); @@ -2740,7 +2740,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag) const char *dot = strchr(flagname, '.'); FFlagDef *fd; - const PClass *cls = self->GetClass(); + PClassActor *cls = self->GetClass(); if (dot != NULL) { @@ -2762,7 +2762,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag) if (fd->structoffset == -1) { - HandleDeprecatedFlags(self, cls->ActorInfo, value, fd->flagbit); + HandleDeprecatedFlags(self, cls, value, fd->flagbit); } else { diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index a3e17351c..45777f061 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -320,10 +320,10 @@ static FFlagDef PlayerPawnFlags[] = static const struct FFlagList { const PClass * const *Type; FFlagDef *Defs; int NumDefs; } FlagLists[] = { - { &RUNTIME_CLASS(AActor), ActorFlags, countof(ActorFlags) }, - { &RUNTIME_CLASS(AInventory), InventoryFlags, countof(InventoryFlags) }, - { &RUNTIME_CLASS(AWeapon), WeaponFlags, countof(WeaponFlags) }, - { &RUNTIME_CLASS(APlayerPawn), PlayerPawnFlags,countof(PlayerPawnFlags) }, + { &RUNTIME_CLASS_CASTLESS(AActor), ActorFlags, countof(ActorFlags) }, + { &RUNTIME_CLASS_CASTLESS(AInventory), InventoryFlags, countof(InventoryFlags) }, + { &RUNTIME_CLASS_CASTLESS(AWeapon), WeaponFlags, countof(WeaponFlags) }, + { &RUNTIME_CLASS_CASTLESS(APlayerPawn), PlayerPawnFlags,countof(PlayerPawnFlags) }, }; #define NUM_FLAG_LISTS (countof(FlagLists)) diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index 33ef4e01b..52cc6509b 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -57,22 +57,22 @@ FRandom pr_exrandom ("EX_Random"); // [GRB] Parses an expression and stores it into Expression array // -static FxExpression *ParseExpressionM (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpressionL (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpressionK (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpressionJ (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpressionI (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpressionH (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpressionG (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpressionF (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpressionE (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpressionD (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpressionC (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpressionB (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpressionA (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpression0 (FScanner &sc, const PClass *cls); +static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpressionL (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpressionK (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpressionJ (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpressionI (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpressionH (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpressionG (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpressionF (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpressionE (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpressionD (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpressionC (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpressionB (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpressionA (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls); -FxExpression *ParseExpression (FScanner &sc, PClass *cls) +FxExpression *ParseExpression (FScanner &sc, PClassActor *cls) { FxExpression *data = ParseExpressionM (sc, cls); @@ -84,7 +84,7 @@ FxExpression *ParseExpression (FScanner &sc, PClass *cls) return data; } -static FxExpression *ParseExpressionM (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls) { FxExpression *condition = ParseExpressionL (sc, cls); @@ -101,7 +101,7 @@ static FxExpression *ParseExpressionM (FScanner &sc, const PClass *cls) } } -static FxExpression *ParseExpressionL (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionL (FScanner &sc, PClassActor *cls) { FxExpression *tmp = ParseExpressionK (sc, cls); @@ -113,7 +113,7 @@ static FxExpression *ParseExpressionL (FScanner &sc, const PClass *cls) return tmp; } -static FxExpression *ParseExpressionK (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionK (FScanner &sc, PClassActor *cls) { FxExpression *tmp = ParseExpressionJ (sc, cls); @@ -125,7 +125,7 @@ static FxExpression *ParseExpressionK (FScanner &sc, const PClass *cls) return tmp; } -static FxExpression *ParseExpressionJ (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionJ (FScanner &sc, PClassActor *cls) { FxExpression *tmp = ParseExpressionI (sc, cls); @@ -137,7 +137,7 @@ static FxExpression *ParseExpressionJ (FScanner &sc, const PClass *cls) return tmp; } -static FxExpression *ParseExpressionI (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionI (FScanner &sc, PClassActor *cls) { FxExpression *tmp = ParseExpressionH (sc, cls); @@ -149,7 +149,7 @@ static FxExpression *ParseExpressionI (FScanner &sc, const PClass *cls) return tmp; } -static FxExpression *ParseExpressionH (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionH (FScanner &sc, PClassActor *cls) { FxExpression *tmp = ParseExpressionG (sc, cls); @@ -161,7 +161,7 @@ static FxExpression *ParseExpressionH (FScanner &sc, const PClass *cls) return tmp; } -static FxExpression *ParseExpressionG (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionG (FScanner &sc, PClassActor *cls) { FxExpression *tmp = ParseExpressionF (sc, cls); @@ -175,7 +175,7 @@ static FxExpression *ParseExpressionG (FScanner &sc, const PClass *cls) return tmp; } -static FxExpression *ParseExpressionF (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionF (FScanner &sc, PClassActor *cls) { FxExpression *tmp = ParseExpressionE (sc, cls); @@ -189,7 +189,7 @@ static FxExpression *ParseExpressionF (FScanner &sc, const PClass *cls) return tmp; } -static FxExpression *ParseExpressionE (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionE (FScanner &sc, PClassActor *cls) { FxExpression *tmp = ParseExpressionD (sc, cls); @@ -203,7 +203,7 @@ static FxExpression *ParseExpressionE (FScanner &sc, const PClass *cls) return tmp; } -static FxExpression *ParseExpressionD (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionD (FScanner &sc, PClassActor *cls) { FxExpression *tmp = ParseExpressionC (sc, cls); @@ -217,7 +217,7 @@ static FxExpression *ParseExpressionD (FScanner &sc, const PClass *cls) return tmp; } -static FxExpression *ParseExpressionC (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionC (FScanner &sc, PClassActor *cls) { FxExpression *tmp = ParseExpressionB (sc, cls); @@ -231,7 +231,7 @@ static FxExpression *ParseExpressionC (FScanner &sc, const PClass *cls) return tmp; } -static FxExpression *ParseExpressionB (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionB (FScanner &sc, PClassActor *cls) { sc.GetToken(); switch(sc.TokenType) @@ -260,7 +260,7 @@ static FxExpression *ParseExpressionB (FScanner &sc, const PClass *cls) // //========================================================================== -static FxExpression *ParseExpressionA (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionA (FScanner &sc, PClassActor *cls) { FxExpression *base_expr = ParseExpression0 (sc, cls); @@ -311,7 +311,7 @@ static FxExpression *ParseExpressionA (FScanner &sc, const PClass *cls) -static FxExpression *ParseExpression0 (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) { FScriptPosition scpos(sc); if (sc.CheckToken('(')) diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 99245d760..ccf73eb34 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -60,11 +60,11 @@ extern PSymbolTable GlobalSymbols; struct FCompileContext { - const PClass *cls; + PClassActor *cls; bool lax; bool isconst; - FCompileContext(const PClass *_cls = NULL, bool _lax = false, bool _isconst = false) + FCompileContext(PClassActor *_cls = NULL, bool _lax = false, bool _isconst = false) { cls = _cls; lax = _lax; @@ -73,7 +73,7 @@ struct FCompileContext PSymbol *FindInClass(FName identifier) { - return cls? cls->Symbols.FindSymbol(identifier, true) : NULL; + return cls ? cls->Symbols.FindSymbol(identifier, true) : NULL; } PSymbol *FindGlobal(FName identifier) { @@ -894,7 +894,7 @@ public: class FxMultiNameState : public FxExpression { - const PClass *scope; + PClassActor *scope; TArray<FName> names; public: @@ -906,7 +906,7 @@ public: -FxExpression *ParseExpression (FScanner &sc, PClass *cls); +FxExpression *ParseExpression (FScanner &sc, PClassActor *cls); #endif diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index e43dbcb5b..78a115c34 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3782,19 +3782,19 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build) FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); - if (ctx.cls->ActorInfo == NULL || ctx.cls->ActorInfo->NumOwnedStates == 0) + if (ctx.cls->NumOwnedStates == 0) { // This can't really happen assert(false); } - if (ctx.cls->ActorInfo->NumOwnedStates <= index) + if (ctx.cls->NumOwnedStates <= index) { ScriptPosition.Message(MSG_ERROR, "%s: Attempt to jump to non existing state index %d", ctx.cls->TypeName.GetChars(), index); delete this; return NULL; } - FxExpression *x = new FxConstant(ctx.cls->ActorInfo->OwnedStates + index, ScriptPosition); + FxExpression *x = new FxConstant(ctx.cls->OwnedStates + index, ScriptPosition); delete this; return x; } @@ -3842,11 +3842,11 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) } else if (names[0] == NAME_Super) { - scope = ctx.cls->ParentClass; + scope = dyn_cast<PClassActor>(ctx.cls->ParentClass); } else { - scope = PClass::FindClass(names[0]); + scope = PClass::FindActor(names[0]); if (scope == NULL) { ScriptPosition.Message(MSG_ERROR, "Unknown class '%s' in state label", names[0].GetChars()); @@ -3866,13 +3866,7 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) // If the label is class specific we can resolve it right here if (names[1] != NAME_None) { - if (scope->ActorInfo == NULL) - { - ScriptPosition.Message(MSG_ERROR, "'%s' has no actorinfo", names[0].GetChars()); - delete this; - return NULL; - } - destination = scope->ActorInfo->FindState(names.Size()-1, &names[1], false); + destination = scope->FindState(names.Size()-1, &names[1], false); if (destination == NULL) { ScriptPosition.Message(ctx.lax? MSG_WARNING:MSG_ERROR, "Unknown state jump destination"); @@ -3904,7 +3898,7 @@ ExpVal FxMultiNameState::EvalExpression (AActor *self) { ExpVal ret; ret.Type = VAL_State; - ret.pointer = self->GetClass()->ActorInfo->FindState(names.Size(), &names[0]); + ret.pointer = self->GetClass()->FindState(names.Size(), &names[0]); if (ret.pointer == NULL) { const char *dot=""; @@ -3932,7 +3926,7 @@ int DecoFindMultiNameState(VMFrameStack *stack, VMValue *param, int numparam, VM names[i - 1] = zaname; } PARAM_OBJECT_AT(0, self, AActor); - FState *state = self->GetClass()->ActorInfo->FindState(numparam - 1, names); + FState *state = self->GetClass()->FindState(numparam - 1, names); if (state == NULL) { const char *dot = ""; @@ -4011,7 +4005,7 @@ FStateExpressions::~FStateExpressions() // //========================================================================== -int FStateExpressions::Add(FxExpression *x, const PClass *o, bool c) +int FStateExpressions::Add(FxExpression *x, PClassActor *o, bool c) { int idx = expressions.Reserve(1); FStateExpression &exp = expressions[idx]; @@ -4028,11 +4022,11 @@ int FStateExpressions::Add(FxExpression *x, const PClass *o, bool c) // //========================================================================== -int FStateExpressions::Reserve(int num, const PClass *cls) +int FStateExpressions::Reserve(int num, PClassActor *cls) { int idx = expressions.Reserve(num); FStateExpression *exp = &expressions[idx]; - for(int i=0; i<num; i++) + for(int i = 0; i < num; i++) { exp[i].expr = NULL; exp[i].owner = cls; diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 9a9d99cc2..0bf7832cc 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -64,7 +64,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def); // //========================================================================== -FxExpression *ParseParameter(FScanner &sc, PClass *cls, char type, bool constant) +FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, char type, bool constant) { FxExpression *x = NULL; int v; @@ -193,7 +193,7 @@ FxExpression *ParseParameter(FScanner &sc, PClass *cls, char type, bool constant // //========================================================================== -static void ParseConstant (FScanner &sc, PSymbolTable * symt, PClass *cls) +static void ParseConstant (FScanner &sc, PSymbolTable * symt, PClassActor *cls) { // Read the type and make sure it's int or float. if (sc.CheckToken(TK_Int) || sc.CheckToken(TK_Float)) @@ -241,7 +241,7 @@ static void ParseConstant (FScanner &sc, PSymbolTable * symt, PClass *cls) // //========================================================================== -static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClass *cls) +static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClassActor *cls) { int currvalue = 0; @@ -282,7 +282,7 @@ static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClass *cls) // //========================================================================== -static void ParseNativeVariable (FScanner &sc, PSymbolTable * symt, PClass *cls) +static void ParseNativeVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cls) { FExpressionType valuetype; @@ -367,7 +367,7 @@ static void ParseNativeVariable (FScanner &sc, PSymbolTable * symt, PClass *cls) // //========================================================================== -static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClass *cls) +static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cls) { FExpressionType valuetype; @@ -453,9 +453,9 @@ void HandleActorFlag(FScanner &sc, Baggage &bag, const char *part1, const char * { FFlagDef *fd; - if ( (fd = FindFlag (bag.Info->Class, part1, part2)) ) + if ( (fd = FindFlag (bag.Info, part1, part2)) ) { - AActor *defaults = (AActor*)bag.Info->Class->Defaults; + AActor *defaults = (AActor*)bag.Info->Defaults; if (fd->structoffset == -1) // this is a deprecated flag that has been changed into a real property { HandleDeprecatedFlags(defaults, bag.Info, mod=='+', fd->flagbit); @@ -582,17 +582,17 @@ static int ParseThingActivation (FScanner &sc) static FState *CheckState(FScanner &sc, PClass *type) { - int v=0; + int v = 0; if (sc.GetString() && !sc.Crossed) { if (sc.Compare("0")) return NULL; else if (sc.Compare("PARENT")) { - FState * state = NULL; + FState *state = NULL; sc.MustGetString(); - FActorInfo * info = type->ParentClass->ActorInfo; + PClassActor *info = dyn_cast<PClassActor>(type->ParentClass); if (info != NULL) { @@ -612,15 +612,17 @@ static FState *CheckState(FScanner &sc, PClass *type) } } - if (state == NULL && v==0) return NULL; - - if (v!=0 && state==NULL) + if (state == NULL && v==0) + { + return NULL; + } + if (v != 0 && state==NULL) { sc.ScriptMessage("Attempt to get invalid state from actor %s\n", type->ParentClass->TypeName.GetChars()); FScriptPosition::ErrorCounter++; return NULL; } - state+=v; + state += v; return state; } else @@ -667,8 +669,8 @@ static bool ParsePropertyParams(FScanner &sc, FPropertyInfo *prop, AActor *defau if (sc.CheckString ("(")) { - FxExpression *x = ParseExpression(sc, bag.Info->Class); - conv.i = 0x40000000 | StateParams.Add(x, bag.Info->Class, false); + FxExpression *x = ParseExpression(sc, bag.Info); + conv.i = 0x40000000 | StateParams.Add(x, bag.Info, false); params.Push(conv); sc.MustGetStringName(")"); break; @@ -849,9 +851,9 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag) if (prop != NULL) { - if (bag.Info->Class->IsDescendantOf(*prop->cls)) + if (bag.Info->IsDescendantOf(*prop->cls)) { - ParsePropertyParams(sc, prop, (AActor *)bag.Info->Class->Defaults, bag); + ParsePropertyParams(sc, prop, (AActor *)bag.Info->Defaults, bag); } else { @@ -861,7 +863,7 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag) } else if (MatchString(propname, statenames) != -1) { - bag.statedef.SetStateLabel(propname, CheckState (sc, bag.Info->Class)); + bag.statedef.SetStateLabel(propname, CheckState (sc, bag.Info)); } else { @@ -879,7 +881,7 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag) // //========================================================================== -static void ParseActionDef (FScanner &sc, PClass *cls) +static void ParseActionDef (FScanner &sc, PClassActor *cls) { enum { @@ -1034,7 +1036,7 @@ static void ParseActionDef (FScanner &sc, PClass *cls) // Starts a new actor definition // //========================================================================== -static FActorInfo *ParseActorHeader(FScanner &sc, Baggage *bag) +static PClassActor *ParseActorHeader(FScanner &sc, Baggage *bag) { FName typeName; FName parentName; @@ -1115,11 +1117,11 @@ static FActorInfo *ParseActorHeader(FScanner &sc, Baggage *bag) try { - FActorInfo *info = CreateNewActor(sc, typeName, parentName, native); - info->DoomEdNum = DoomEdNum > 0? DoomEdNum : -1; + PClassActor *info = CreateNewActor(sc, typeName, parentName, native); + info->DoomEdNum = DoomEdNum > 0 ? DoomEdNum : -1; SetReplacement(info, replaceName); - ResetBaggage (bag, info->Class->ParentClass); + ResetBaggage (bag, info == RUNTIME_CLASS(AActor) ? NULL : static_cast<PClassActor *>(info->ParentClass)); bag->Info = info; bag->Lumpnum = sc.LumpNum; #ifdef _DEBUG @@ -1141,7 +1143,7 @@ static FActorInfo *ParseActorHeader(FScanner &sc, Baggage *bag) //========================================================================== static void ParseActor(FScanner &sc) { - FActorInfo * info=NULL; + PClassActor *info = NULL; Baggage bag; info = ParseActorHeader(sc, &bag); @@ -1151,23 +1153,23 @@ static void ParseActor(FScanner &sc) switch (sc.TokenType) { case TK_Action: - ParseActionDef (sc, info->Class); + ParseActionDef (sc, info); break; case TK_Const: - ParseConstant (sc, &info->Class->Symbols, info->Class); + ParseConstant (sc, &info->Symbols, info); break; case TK_Enum: - ParseEnum (sc, &info->Class->Symbols, info->Class); + ParseEnum (sc, &info->Symbols, info); break; case TK_Native: - ParseNativeVariable (sc, &info->Class->Symbols, info->Class); + ParseNativeVariable (sc, &info->Symbols, info); break; case TK_Var: - ParseUserVariable (sc, &info->Class->Symbols, info->Class); + ParseUserVariable (sc, &info->Symbols, info); break; case TK_Identifier: @@ -1177,10 +1179,10 @@ static void ParseActor(FScanner &sc) case TK_States: if (bag.StateSet) { - sc.ScriptMessage("'%s' contains multiple state declarations", bag.Info->Class->TypeName.GetChars()); + sc.ScriptMessage("'%s' contains multiple state declarations", bag.Info->TypeName.GetChars()); FScriptPosition::ErrorCounter++; } - ParseStates(sc, bag.Info, (AActor *)bag.Info->Class->Defaults, bag); + ParseStates(sc, bag.Info, (AActor *)bag.Info->Defaults, bag); bag.StateSet = true; break; @@ -1190,7 +1192,7 @@ static void ParseActor(FScanner &sc) break; default: - sc.ScriptError("Unexpected '%s' in definition of '%s'", sc.String, bag.Info->Class->TypeName.GetChars()); + sc.ScriptError("Unexpected '%s' in definition of '%s'", sc.String, bag.Info->TypeName.GetChars()); break; } } diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index cd2537db0..9690756b5 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -74,7 +74,7 @@ // Gets a class pointer and performs an error check for correct type // //========================================================================== -static const PClass *FindClassTentative(const char *name, const char *ancestor) +static PClassActor *FindClassTentative(const char *name, const char *ancestor) { // "" and "none" mean 'no class' if (name == NULL || *name == 0 || !stricmp(name, "none")) @@ -82,15 +82,15 @@ static const PClass *FindClassTentative(const char *name, const char *ancestor) return NULL; } - const PClass *anc = PClass::FindClass(ancestor); + PClass *anc = PClass::FindClass(ancestor); assert(anc != NULL); // parent classes used here should always be natively defined - const PClass *cls = const_cast<PClass*>(anc)->FindClassTentative(name); + PClass *cls = anc->FindClassTentative(name); assert (cls != NULL); // cls can not ne NULL here if (!cls->IsDescendantOf(anc)) { I_Error("%s does not inherit from %s\n", name, ancestor); } - return cls; + return static_cast<PClassActor *>(cls); } //=========================================================================== @@ -103,7 +103,7 @@ static const PClass *FindClassTentative(const char *name, const char *ancestor) // properties is not recommended // //=========================================================================== -void HandleDeprecatedFlags(AActor *defaults, FActorInfo *info, bool set, int index) +void HandleDeprecatedFlags(AActor *defaults, PClassActor *info, bool set, int index) { switch (index) { @@ -250,18 +250,22 @@ DEFINE_INFO_PROPERTY(conversationid, IiI, Actor) if (PROP_PARM_COUNT > 1) { if ((gameinfo.flags & (GI_SHAREWARE|GI_TEASER2)) == (GI_SHAREWARE)) - convid=id1; + convid = id1; if ((gameinfo.flags & (GI_SHAREWARE|GI_TEASER2)) == (GI_SHAREWARE|GI_TEASER2)) - convid=id2; + convid = id2; - if (convid==-1) return; + if (convid == -1) + return; } - if (convid<0 || convid>1000) + if (convid < 0 || convid > 1000) { I_Error ("ConversationID must be in the range [0,1000]"); } - else StrifeTypes[convid] = info->Class; + else + { + StrifeTypes[convid] = info; + } } //========================================================================== @@ -275,10 +279,10 @@ DEFINE_INFO_PROPERTY(conversationid, IiI, Actor) //========================================================================== DEFINE_PROPERTY(skip_super, 0, Actor) { - if (info->Class->IsDescendantOf(RUNTIME_CLASS(AInventory))) + if (info->IsDescendantOf(RUNTIME_CLASS(AInventory))) { bag.ScriptPosition.Message(MSG_WARNING, - "'skip_super' in definition of inventory item '%s' ignored.", info->Class->TypeName.GetChars() ); + "'skip_super' in definition of inventory item '%s' ignored.", info->TypeName.GetChars() ); return; } if (bag.StateSet) @@ -320,7 +324,7 @@ DEFINE_PROPERTY(health, I, Actor) DEFINE_PROPERTY(gibhealth, I, Actor) { PROP_INT_PARM(id, 0); - info->Class->Meta.SetMetaInt (AMETA_GibHealth, id); + info->Meta.SetMetaInt (AMETA_GibHealth, id); } //========================================================================== @@ -329,7 +333,7 @@ DEFINE_PROPERTY(gibhealth, I, Actor) DEFINE_PROPERTY(woundhealth, I, Actor) { PROP_INT_PARM(id, 0); - info->Class->Meta.SetMetaInt (AMETA_WoundHealth, id); + info->Meta.SetMetaInt (AMETA_WoundHealth, id); } //========================================================================== @@ -552,7 +556,7 @@ DEFINE_PROPERTY(activesound, S, Actor) DEFINE_PROPERTY(howlsound, S, Actor) { PROP_STRING_PARM(str, 0); - info->Class->Meta.SetMetaInt (AMETA_HowlSound, S_FindSound(str)); + info->Meta.SetMetaInt (AMETA_HowlSound, S_FindSound(str)); } //========================================================================== @@ -633,7 +637,7 @@ DEFINE_PROPERTY(alpha, F, Actor) DEFINE_PROPERTY(obituary, S, Actor) { PROP_STRING_PARM(str, 0); - info->Class->Meta.SetMetaString (AMETA_Obituary, str); + info->Meta.SetMetaString (AMETA_Obituary, str); } //========================================================================== @@ -642,7 +646,7 @@ DEFINE_PROPERTY(obituary, S, Actor) DEFINE_PROPERTY(hitobituary, S, Actor) { PROP_STRING_PARM(str, 0); - info->Class->Meta.SetMetaString (AMETA_HitObituary, str); + info->Meta.SetMetaString (AMETA_HitObituary, str); } //========================================================================== @@ -650,7 +654,7 @@ DEFINE_PROPERTY(hitobituary, S, Actor) //========================================================================== DEFINE_PROPERTY(donthurtshooter, 0, Actor) { - info->Class->Meta.SetMetaInt (ACMETA_DontHurtShooter, true); + info->Meta.SetMetaInt (ACMETA_DontHurtShooter, true); } //========================================================================== @@ -659,7 +663,7 @@ DEFINE_PROPERTY(donthurtshooter, 0, Actor) DEFINE_PROPERTY(explosionradius, I, Actor) { PROP_INT_PARM(id, 0); - info->Class->Meta.SetMetaInt (ACMETA_ExplosionRadius, id); + info->Meta.SetMetaInt (ACMETA_ExplosionRadius, id); } //========================================================================== @@ -668,7 +672,7 @@ DEFINE_PROPERTY(explosionradius, I, Actor) DEFINE_PROPERTY(explosiondamage, I, Actor) { PROP_INT_PARM(id, 0); - info->Class->Meta.SetMetaInt (ACMETA_ExplosionDamage, id); + info->Meta.SetMetaInt (ACMETA_ExplosionDamage, id); } //========================================================================== @@ -679,7 +683,7 @@ DEFINE_PROPERTY(deathheight, F, Actor) PROP_FIXED_PARM(h, 0); // AActor::Die() uses a height of 0 to mean "cut the height to 1/4", // so if a height of 0 is desired, store it as -1. - info->Class->Meta.SetMetaFixed (AMETA_DeathHeight, h <= 0 ? -1 : h); + info->Meta.SetMetaFixed (AMETA_DeathHeight, h <= 0 ? -1 : h); } //========================================================================== @@ -689,7 +693,7 @@ DEFINE_PROPERTY(burnheight, F, Actor) { PROP_FIXED_PARM(h, 0); // The note above for AMETA_DeathHeight also applies here. - info->Class->Meta.SetMetaFixed (AMETA_BurnHeight, h <= 0 ? -1 : h); + info->Meta.SetMetaFixed (AMETA_BurnHeight, h <= 0 ? -1 : h); } //========================================================================== @@ -716,7 +720,7 @@ DEFINE_PROPERTY(meleethreshold, F, Actor) DEFINE_PROPERTY(meleedamage, I, Actor) { PROP_INT_PARM(id, 0); - info->Class->Meta.SetMetaInt (ACMETA_MeleeDamage, id); + info->Meta.SetMetaInt (ACMETA_MeleeDamage, id); } //========================================================================== @@ -734,7 +738,7 @@ DEFINE_PROPERTY(meleerange, F, Actor) DEFINE_PROPERTY(meleesound, S, Actor) { PROP_STRING_PARM(str, 0); - info->Class->Meta.SetMetaInt (ACMETA_MeleeSound, S_FindSound(str)); + info->Meta.SetMetaInt (ACMETA_MeleeSound, S_FindSound(str)); } //========================================================================== @@ -743,7 +747,7 @@ DEFINE_PROPERTY(meleesound, S, Actor) DEFINE_PROPERTY(missiletype, S, Actor) { PROP_STRING_PARM(str, 0); - info->Class->Meta.SetMetaInt (ACMETA_MissileName, FName(str)); + info->Meta.SetMetaInt (ACMETA_MissileName, FName(str)); } //========================================================================== @@ -752,7 +756,7 @@ DEFINE_PROPERTY(missiletype, S, Actor) DEFINE_PROPERTY(missileheight, F, Actor) { PROP_FIXED_PARM(id, 0); - info->Class->Meta.SetMetaFixed (ACMETA_MissileHeight, id); + info->Meta.SetMetaFixed (ACMETA_MissileHeight, id); } //========================================================================== @@ -822,7 +826,7 @@ DEFINE_PROPERTY(bloodcolor, C, Actor) PalEntry pe = color; pe.a = CreateBloodTranslation(pe); - info->Class->Meta.SetMetaInt (AMETA_BloodColor, pe); + info->Meta.SetMetaInt (AMETA_BloodColor, pe); } @@ -837,21 +841,21 @@ DEFINE_PROPERTY(bloodtype, Sss, Actor) FName blood = str; // normal blood - info->Class->Meta.SetMetaInt (AMETA_BloodType, blood); + info->Meta.SetMetaInt (AMETA_BloodType, blood); if (PROP_PARM_COUNT > 1) { blood = str1; } // blood splatter - info->Class->Meta.SetMetaInt (AMETA_BloodType2, blood); + info->Meta.SetMetaInt (AMETA_BloodType2, blood); if (PROP_PARM_COUNT > 2) { blood = str2; } // axe blood - info->Class->Meta.SetMetaInt (AMETA_BloodType3, blood); + info->Meta.SetMetaInt (AMETA_BloodType3, blood); } //========================================================================== @@ -996,7 +1000,7 @@ DEFINE_PROPERTY(maxdropoffheight, F, Actor) DEFINE_PROPERTY(poisondamage, I, Actor) { PROP_INT_PARM(i, 0); - info->Class->Meta.SetMetaInt (AMETA_PoisonDamage, i); + info->Meta.SetMetaInt (AMETA_PoisonDamage, i); } //========================================================================== @@ -1005,7 +1009,7 @@ DEFINE_PROPERTY(poisondamage, I, Actor) DEFINE_PROPERTY(fastspeed, F, Actor) { PROP_FIXED_PARM(i, 0); - info->Class->Meta.SetMetaFixed (AMETA_FastSpeed, i); + info->Meta.SetMetaFixed (AMETA_FastSpeed, i); } //========================================================================== @@ -1014,7 +1018,7 @@ DEFINE_PROPERTY(fastspeed, F, Actor) DEFINE_PROPERTY(radiusdamagefactor, F, Actor) { PROP_FIXED_PARM(i, 0); - info->Class->Meta.SetMetaFixed (AMETA_RDFactor, i); + info->Meta.SetMetaFixed (AMETA_RDFactor, i); } //========================================================================== @@ -1023,7 +1027,7 @@ DEFINE_PROPERTY(radiusdamagefactor, F, Actor) DEFINE_PROPERTY(cameraheight, F, Actor) { PROP_FIXED_PARM(i, 0); - info->Class->Meta.SetMetaFixed (AMETA_CameraHeight, i); + info->Meta.SetMetaFixed (AMETA_CameraHeight, i); } //========================================================================== @@ -1131,7 +1135,7 @@ DEFINE_CLASS_PROPERTY(backpackmaxamount, I, Ammo) DEFINE_CLASS_PROPERTY(dropamount, I, Ammo) { PROP_INT_PARM(i, 0); - info->Class->Meta.SetMetaInt (AIMETA_DropAmount, i); + info->Meta.SetMetaInt (AIMETA_DropAmount, i); } //========================================================================== @@ -1169,11 +1173,11 @@ DEFINE_CLASS_PROPERTY(saveamount, I, Armor) PROP_INT_PARM(i, 0); // Special case here because this property has to work for 2 unrelated classes - if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup))) + if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup))) { ((ABasicArmorPickup*)defaults)->SaveAmount=i; } - else if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))) + else if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))) { ((ABasicArmorBonus*)defaults)->SaveAmount=i; } @@ -1192,11 +1196,11 @@ DEFINE_CLASS_PROPERTY(savepercent, F, Armor) i = clamp(i, 0, 100*FRACUNIT)/100; // Special case here because this property has to work for 2 unrelated classes - if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup))) + if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup))) { ((ABasicArmorPickup*)defaults)->SavePercent = i; } - else if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))) + else if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))) { ((ABasicArmorBonus*)defaults)->SavePercent = i; } @@ -1214,11 +1218,11 @@ DEFINE_CLASS_PROPERTY(maxabsorb, I, Armor) PROP_INT_PARM(i, 0); // Special case here because this property has to work for 2 unrelated classes - if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup))) + if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup))) { ((ABasicArmorPickup*)defaults)->MaxAbsorb = i; } - else if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))) + else if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))) { ((ABasicArmorBonus*)defaults)->MaxAbsorb = i; } @@ -1236,11 +1240,11 @@ DEFINE_CLASS_PROPERTY(maxfullabsorb, I, Armor) PROP_INT_PARM(i, 0); // Special case here because this property has to work for 2 unrelated classes - if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup))) + if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup))) { ((ABasicArmorPickup*)defaults)->MaxFullAbsorb = i; } - else if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))) + else if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))) { ((ABasicArmorBonus*)defaults)->MaxFullAbsorb = i; } @@ -1275,7 +1279,7 @@ DEFINE_CLASS_PROPERTY(icon, S, Inventory) !(gameinfo.flags&GI_SHAREWARE) && Wads.GetLumpFile(bag.Lumpnum) != 0) { bag.ScriptPosition.Message(MSG_WARNING, - "Icon '%s' for '%s' not found\n", i, info->Class->TypeName.GetChars()); + "Icon '%s' for '%s' not found\n", i, info->TypeName.GetChars()); } } } @@ -1322,7 +1326,7 @@ DEFINE_CLASS_PROPERTY(pickupflash, S, Inventory) DEFINE_CLASS_PROPERTY(pickupmessage, T, Inventory) { PROP_STRING_PARM(str, 0); - info->Class->Meta.SetMetaString(AIMETA_PickupMessage, str); + info->Meta.SetMetaString(AIMETA_PickupMessage, str); } //========================================================================== @@ -1365,7 +1369,7 @@ DEFINE_CLASS_PROPERTY(usesound, S, Inventory) DEFINE_CLASS_PROPERTY(givequest, I, Inventory) { PROP_INT_PARM(i, 0); - info->Class->Meta.SetMetaInt(AIMETA_GiveQuest, i); + info->Meta.SetMetaInt(AIMETA_GiveQuest, i); } //========================================================================== @@ -1375,8 +1379,8 @@ DEFINE_CLASS_PROPERTY(lowmessage, IT, Health) { PROP_INT_PARM(i, 0); PROP_STRING_PARM(str, 1); - info->Class->Meta.SetMetaInt(AIMETA_LowHealth, i); - info->Class->Meta.SetMetaString(AIMETA_LowHealthMessage, str); + info->Meta.SetMetaInt(AIMETA_LowHealth, i); + info->Meta.SetMetaString(AIMETA_LowHealthMessage, str); } //========================================================================== @@ -1403,7 +1407,7 @@ DEFINE_CLASS_PROPERTY(number, I, PuzzleItem) DEFINE_CLASS_PROPERTY(failmessage, T, PuzzleItem) { PROP_STRING_PARM(str, 0); - info->Class->Meta.SetMetaString(AIMETA_PuzzFailMessage, str); + info->Meta.SetMetaString(AIMETA_PuzzFailMessage, str); } //========================================================================== @@ -1558,7 +1562,7 @@ DEFINE_CLASS_PROPERTY(yadjust, F, Weapon) DEFINE_CLASS_PROPERTY(slotnumber, I, Weapon) { PROP_INT_PARM(i, 0); - info->Class->Meta.SetMetaInt(AWMETA_SlotNumber, i); + info->Meta.SetMetaInt(AWMETA_SlotNumber, i); } //========================================================================== @@ -1567,7 +1571,7 @@ DEFINE_CLASS_PROPERTY(slotnumber, I, Weapon) DEFINE_CLASS_PROPERTY(slotpriority, F, Weapon) { PROP_FIXED_PARM(i, 0); - info->Class->Meta.SetMetaFixed(AWMETA_SlotPriority, i); + info->Meta.SetMetaFixed(AWMETA_SlotPriority, i); } //========================================================================== @@ -1599,11 +1603,11 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory) int alpha; PalEntry * pBlendColor; - if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerup))) + if (info->IsDescendantOf(RUNTIME_CLASS(APowerup))) { pBlendColor = &((APowerup*)defaults)->BlendColor; } - else if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) + else if (info->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) { pBlendColor = &((APowerupGiver*)defaults)->BlendColor; } @@ -1649,11 +1653,11 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, colormap, FFFfff, Inventory) { PalEntry * pBlendColor; - if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerup))) + if (info->IsDescendantOf(RUNTIME_CLASS(APowerup))) { pBlendColor = &((APowerup*)defaults)->BlendColor; } - else if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) + else if (info->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) { pBlendColor = &((APowerupGiver*)defaults)->BlendColor; } @@ -1693,11 +1697,11 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, duration, I, Inventory) { int *pEffectTics; - if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerup))) + if (info->IsDescendantOf(RUNTIME_CLASS(APowerup))) { pEffectTics = &((APowerup*)defaults)->EffectTics; } - else if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) + else if (info->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) { pEffectTics = &((APowerupGiver*)defaults)->EffectTics; } @@ -1718,11 +1722,11 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, strength, F, Inventory) { fixed_t *pStrength; - if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerup))) + if (info->IsDescendantOf(RUNTIME_CLASS(APowerup))) { pStrength = &((APowerup*)defaults)->Strength; } - else if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) + else if (info->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) { pStrength = &((APowerupGiver*)defaults)->Strength; } @@ -1743,11 +1747,11 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, mode, S, Inventory) { PROP_STRING_PARM(str, 0); FName *pMode; - if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerup))) + if (info->IsDescendantOf(RUNTIME_CLASS(APowerup))) { pMode = &((APowerup*)defaults)->Mode; } - else if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) + else if (info->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) { pMode = &((APowerupGiver*)defaults)->Mode; } @@ -1768,7 +1772,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, type, S, PowerupGiver) // Yuck! What was I thinking when I decided to prepend "Power" to the name? // Now it's too late to change it... - const PClass *cls = PClass::FindClass(str); + PClassActor *cls = PClass::FindActor(str); if (cls == NULL || !cls->IsDescendantOf(RUNTIME_CLASS(APowerup))) { FString st; @@ -1791,7 +1795,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, type, S, PowerupGiver) DEFINE_CLASS_PROPERTY_PREFIX(player, displayname, S, PlayerPawn) { PROP_STRING_PARM(str, 0); - info->Class->Meta.SetMetaString (APMETA_DisplayName, str); + info->Meta.SetMetaString (APMETA_DisplayName, str); } //========================================================================== @@ -1803,7 +1807,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, soundclass, S, PlayerPawn) FString tmp = str; tmp.ReplaceChars (' ', '_'); - info->Class->Meta.SetMetaString (APMETA_SoundClass, tmp); + info->Meta.SetMetaString (APMETA_SoundClass, tmp); } //========================================================================== @@ -1819,7 +1823,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, face, S, PlayerPawn) { bag.ScriptPosition.Message(MSG_WARNING, "Invalid face '%s' for '%s';\nSTF replacement codes must be 3 characters.\n", - tmp.GetChars(), info->Class->TypeName.GetChars ()); + tmp.GetChars(), info->TypeName.GetChars ()); } bool valid = ( @@ -1831,10 +1835,10 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, face, S, PlayerPawn) { bag.ScriptPosition.Message(MSG_WARNING, "Invalid face '%s' for '%s';\nSTF replacement codes must be alphanumeric.\n", - tmp.GetChars(), info->Class->TypeName.GetChars ()); + tmp.GetChars(), info->TypeName.GetChars ()); } - info->Class->Meta.SetMetaString (APMETA_Face, tmp); + info->Meta.SetMetaString (APMETA_Face, tmp); } //========================================================================== @@ -1848,7 +1852,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorrange, I_I, PlayerPawn) if (start > end) swap (start, end); - info->Class->Meta.SetMetaInt (APMETA_ColorRange, (start & 255) | ((end & 255) << 8)); + info->Meta.SetMetaInt (APMETA_ColorRange, (start & 255) | ((end & 255) << 8)); } //========================================================================== @@ -1983,7 +1987,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, scoreicon, S, PlayerPawn) if (!defaults->ScoreIcon.isValid()) { bag.ScriptPosition.Message(MSG_WARNING, - "Icon '%s' for '%s' not found\n", z, info->Class->TypeName.GetChars ()); + "Icon '%s' for '%s' not found\n", z, info->TypeName.GetChars ()); } } @@ -2052,7 +2056,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn) DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn) { PROP_STRING_PARM(str, 0); - info->Class->Meta.SetMetaInt (APMETA_InvulMode, (FName)str); + info->Meta.SetMetaInt (APMETA_InvulMode, (FName)str); } //========================================================================== @@ -2061,7 +2065,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn) DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn) { PROP_STRING_PARM(str, 0); - info->Class->Meta.SetMetaInt (APMETA_HealingRadius, (FName)str); + info->Meta.SetMetaInt (APMETA_HealingRadius, (FName)str); } //========================================================================== @@ -2072,7 +2076,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn) for (int i=0;i<5;i++) { PROP_FIXED_PARM(val, i); - info->Class->Meta.SetMetaFixed (APMETA_Hexenarmor0+i, val); + info->Meta.SetMetaFixed (APMETA_Hexenarmor0+i, val); } } @@ -2096,7 +2100,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, weaponslot, ISsssssssssssssssssssssssssssss PROP_STRING_PARM(str, i); weapons << ' ' << str; } - info->Class->Meta.SetMetaString(APMETA_Slot0 + slot, &weapons[1]); + info->Meta.SetMetaString(APMETA_Slot0 + slot, &weapons[1]); } } diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index 6d0a12d1a..6aeec63f8 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -82,7 +82,7 @@ bool DoActionSpecials(FScanner &sc, FState & state, Baggage &bag, FStateTempCall { for (i = 0; i < 5;) { - tcall->Parameters.Push(new FxParameter(new FxIntCast(ParseExpression(sc, bag.Info->Class)))); + tcall->Parameters.Push(new FxParameter(new FxIntCast(ParseExpression(sc, bag.Info)))); i++; if (!sc.CheckToken (',')) break; } @@ -136,7 +136,7 @@ static FString ParseStateString(FScanner &sc) // parses a state block // //========================================================================== -void ParseStates(FScanner &sc, FActorInfo * actor, AActor * defaults, Baggage &bag) +void ParseStates(FScanner &sc, PClassActor * actor, AActor * defaults, Baggage &bag) { FString statestring; FState state; @@ -272,7 +272,7 @@ do_stop: goto endofstate; } - PSymbol *sym = bag.Info->Class->Symbols.FindSymbol (FName(sc.String, true), true); + PSymbol *sym = bag.Info->Symbols.FindSymbol (FName(sc.String, true), true); if (sym != NULL && sym->SymbolType == SYM_ActionFunction) { PSymbolActionFunction *afd = static_cast<PSymbolActionFunction *>(sym); @@ -341,7 +341,7 @@ do_stop: else { // Use the generic parameter parser for everything else - x = ParseParameter(sc, bag.Info->Class, *params, false); + x = ParseParameter(sc, bag.Info, *params, false); } // StateParams.Set(paramindex++, x); tcall->Parameters.Push(new FxParameter(x)); @@ -357,7 +357,7 @@ do_stop: goto endofstate; } params--; - StateParams.Reserve(1, bag.Info->Class); + StateParams.Reserve(1, bag.Info); } else if ((islower(*params) || *params=='!') && sc.CheckString(")")) { @@ -391,7 +391,7 @@ endofstate: } if (tcall->Function != NULL) { - tcall->ActorInfo = actor; + tcall->ActorClass = actor; tcall->FirstState = bag.statedef.GetStateCount() - count; tcall->NumStates = count; StateTempCalls.Push(tcall); diff --git a/src/zscript/vm.h b/src/zscript/vm.h index c7d3e302f..41284f912 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -873,7 +873,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction #define PARAM_STATE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].a == NULL)); FState *x = (FState *)param[p].a; #define PARAM_POINTER_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)param[p].a; #define PARAM_OBJECT_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); type *x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); -#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); PClass *x = (PClass *)param[p].a; assert(x != NULL && x->IsDescendantOf(RUNTIME_CLASS(base))); +#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x != NULL && x->IsDescendantOf(RUNTIME_CLASS(base))); // For optional paramaters. These have dangling elses for you to fill in the default assignment. e.g.: // PARAM_INT_OPT(0,myint) { myint = 55; } @@ -891,7 +891,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction #define PARAM_STATE_OPT_AT(p,x) FState *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].a == NULL)); x = (FState *)param[p].a; } else #define PARAM_POINTER_OPT_AT(p,x,type) type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER); x = (type *)param[p].a; } else #define PARAM_OBJECT_OPT_AT(p,x,type) type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); } else -#define PARAM_CLASS_OPT_AT(p,x,base) PClass *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (PClass *)param[p].a; assert(x != NULL && x->IsDescendantOf(RUNTIME_CLASS(base))); } else +#define PARAM_CLASS_OPT_AT(p,x,base) base::MetaClass *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (base::MetaClass *)param[p].a; assert(x != NULL && x->IsDescendantOf(RUNTIME_CLASS(base))); } else // The above, but with an automatically increasing position index. #define PARAM_PROLOGUE int paramnum = -1; From 604b5ef673d88bcf51fa5dbf3f06904f3b0a52f3 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Thu, 25 Mar 2010 20:38:00 +0000 Subject: [PATCH 025/232] - Removed the old meta data system. All meta data is now stored in subclasses of PClass. This should simplify scripting, since it means that meta fields can be treated (mostly) the same as normal fields. SVN r2242 (scripting) --- src/actor.h | 53 ++------ src/d_dehacked.cpp | 22 ++-- src/d_net.cpp | 14 +-- src/d_netinfo.cpp | 14 +-- src/d_player.h | 50 ++++---- src/dobject.cpp | 128 ------------------- src/dobject.h | 65 ++-------- src/dobjtype.cpp | 97 ++++++++------ src/dobjtype.h | 3 +- src/g_doom/a_bossbrain.cpp | 12 +- src/g_doom/a_doomweaps.cpp | 8 +- src/g_doom/a_revenant.cpp | 2 +- src/g_heretic/a_dsparil.cpp | 6 +- src/g_heretic/a_hereticweaps.cpp | 24 ++-- src/g_heretic/a_wizard.cpp | 2 +- src/g_hexen/a_bats.cpp | 2 +- src/g_hexen/a_clericholy.cpp | 7 +- src/g_hexen/a_fighterhammer.cpp | 2 +- src/g_hexen/a_healingradius.cpp | 7 +- src/g_hexen/a_heresiarch.cpp | 6 +- src/g_hexen/a_iceguy.cpp | 2 +- src/g_hexen/a_korax.cpp | 7 +- src/g_hexen/a_magelightning.cpp | 13 +- src/g_hexen/a_summon.cpp | 2 +- src/g_raven/a_minotaur.cpp | 2 +- src/g_shared/a_action.cpp | 4 +- src/g_shared/a_artifacts.cpp | 6 +- src/g_shared/a_fastprojectile.cpp | 2 +- src/g_shared/a_morph.cpp | 16 ++- src/g_shared/a_morph.h | 2 +- src/g_shared/a_pickups.cpp | 78 ++++++++++-- src/g_shared/a_pickups.h | 113 +++++++++++------ src/g_shared/a_puzzleitems.cpp | 17 ++- src/g_shared/a_randomspawner.cpp | 14 +-- src/g_shared/a_weaponpiece.h | 2 +- src/g_shared/a_weapons.cpp | 107 +++++++++------- src/g_shared/sbarinfo_commands.cpp | 2 +- src/g_shared/shared_hud.cpp | 29 ++--- src/g_strife/a_crusader.cpp | 12 +- src/g_strife/a_inquisitor.cpp | 4 +- src/g_strife/a_sentinel.cpp | 2 +- src/g_strife/a_strifeweapons.cpp | 16 +-- src/info.cpp | 65 +++++++++- src/info.h | 31 +++++ src/m_cheat.cpp | 8 +- src/m_cheat.h | 5 +- src/m_menu.cpp | 13 +- src/p_acs.cpp | 4 +- src/p_enemy.cpp | 9 +- src/p_interaction.cpp | 43 +++---- src/p_local.h | 18 +-- src/p_map.cpp | 10 +- src/p_mobj.cpp | 117 +++++++++-------- src/p_user.cpp | 116 ++++++++++------- src/r_main.cpp | 2 +- src/r_things.cpp | 43 +++---- src/textures/textures.h | 4 +- src/thingdef/olddecorations.cpp | 12 +- src/thingdef/thingdef.cpp | 12 +- src/thingdef/thingdef.h | 11 +- src/thingdef/thingdef_codeptr.cpp | 26 ++-- src/thingdef/thingdef_properties.cpp | 181 ++++++++++++++++----------- 62 files changed, 903 insertions(+), 803 deletions(-) diff --git a/src/actor.h b/src/actor.h index c16080f79..1dcf22c9b 100644 --- a/src/actor.h +++ b/src/actor.h @@ -492,48 +492,17 @@ struct line_t; struct secplane_t; struct FStrifeDialogueNode; -enum -{ - AMETA_BASE = 0x12000, - - AMETA_Obituary, // string (player was killed by this actor) - AMETA_HitObituary, // string (player was killed by this actor in melee) - AMETA_DeathHeight, // fixed (height on normal death) - AMETA_BurnHeight, // fixed (height on burning death) - AMETA_StrifeName, // string (for named Strife objects) - AMETA_BloodColor, // colorized blood - AMETA_GibHealth, // negative health below which this monster dies an extreme death - AMETA_WoundHealth, // health needed to enter wound state - AMETA_PoisonDamage, // Amount of poison damage - AMETA_FastSpeed, // Speed in fast mode - AMETA_RDFactor, // Radius damage factor - AMETA_CameraHeight, // Height of camera when used as such - AMETA_HowlSound, // Sound being played when electrocuted or poisoned - AMETA_BloodType, // Blood replacement type - AMETA_BloodType2, // Bloodsplatter replacement type - AMETA_BloodType3, // AxeBlood replacement type -}; - -struct FDropItem -{ - FName Name; - int probability; - int amount; - FDropItem * Next; -}; - -class FDropItemPtrArray : public TArray<FDropItem *> +class DDropItem : public DObject { + DECLARE_CLASS(DDropItem, DObject) + HAS_OBJECT_POINTERS public: - ~FDropItemPtrArray(); + DDropItem *Next; + FName Name; + int Probability; + int Amount; }; -extern FDropItemPtrArray DropItemList; - -void FreeDropItemChain(FDropItem *chain); -int StoreDropItemChain(FDropItem *chain); - - // Map Object definition. class AActor : public DThinker @@ -556,7 +525,7 @@ public: return (AActor *)(RUNTIME_TYPE(this)->Defaults); } - FDropItem *GetDropItems(); + DDropItem *GetDropItems() const; // Return true if the monster should use a missile attack, false for melee bool SuggestMissileAttack (fixed_t dist); @@ -702,7 +671,11 @@ public: void Crash(); // Return starting health adjusted by skill level - int SpawnHealth(); + int SpawnHealth() const; + + int GetGibHealth() const; + + fixed_t GetCameraHeight() const; // Check for monsters that count as kill but excludes all friendlies. bool CountsAsKill() const diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index fd2d23514..5a9e10145 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -142,7 +142,7 @@ struct StyleName static TArray<StyleName> StyleNames; -static TArray<PClassActor *> AmmoNames; +static TArray<PClassAmmo *> AmmoNames; static TArray<PClassActor *> WeaponNames; // DeHackEd trickery to support MBF-style parameters @@ -1869,18 +1869,14 @@ static int PatchMisc (int dummy) player->health = deh.StartHealth; // Hm... I'm not sure that this is the right way to change this info... - unsigned int index = PClass::FindClass(NAME_DoomPlayer)->Meta.GetMetaInt (ACMETA_DropItems) - 1; - if (index >= 0 && index < DropItemList.Size()) + DDropItem *di = PClass::FindActor(NAME_DoomPlayer)->DropItems; + while (di != NULL) { - FDropItem * di = DropItemList[index]; - while (di != NULL) + if (di->Name == NAME_Clip) { - if (di->Name == NAME_Clip) - { - di->amount = deh.StartBullets; - } - di = di->Next; + di->Amount = deh.StartBullets; } + di = di->Next; } } @@ -2780,12 +2776,12 @@ static bool LoadDehSupp () } else { - PClass *cls = PClass::FindClass(sc.String); - if (cls == NULL || cls->ParentClass != RUNTIME_CLASS(AAmmo)) + PClassAmmo *cls = dyn_cast<PClassAmmo>(PClass::FindClass(sc.String)); + if (cls == NULL) { sc.ScriptError("Unknown ammo type '%s'", sc.String); } - AmmoNames.Push(static_cast<PClassActor *>(cls)); + AmmoNames.Push(cls); } if (sc.CheckString("}")) break; sc.MustGetStringName(","); diff --git a/src/d_net.cpp b/src/d_net.cpp index 6c874f7b9..226baf9ba 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2099,7 +2099,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_SUMMONFRIEND2: case DEM_SUMMONFOE2: { - const PClass *typeinfo; + PClassActor *typeinfo; int angle = 0; SWORD tid = 0; BYTE special = 0; @@ -2114,8 +2114,8 @@ void Net_DoCommand (int type, BYTE **stream, int player) for(i = 0; i < 5; i++) args[i] = ReadLong(stream); } - typeinfo = PClass::FindClass (s); - if (typeinfo != NULL && typeinfo->IsKindOf(RUNTIME_CLASS(PClassActor))) + typeinfo = PClass::FindActor(s); + if (typeinfo != NULL) { AActor *source = players[player].mo; if (source != NULL) @@ -2318,7 +2318,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_MORPHEX: { s = ReadString (stream); - const char *msg = cht_Morph (players + player, PClass::FindClass (s), false); + const char *msg = cht_Morph (players + player, dyn_cast<PClassPlayerPawn>(PClass::FindClass (s)), false); if (player == consoleplayer) { Printf ("%s\n", *msg != '\0' ? msg : "Morph failed."); @@ -2383,7 +2383,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) } for(int i = 0; i < count; ++i) { - PClassActor *wpn = Net_ReadWeapon(stream); + PClassWeapon *wpn = Net_ReadWeapon(stream); players[player].weapons.AddSlot(slot, wpn, player == consoleplayer); } } @@ -2392,7 +2392,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_ADDSLOT: { int slot = ReadByte(stream); - PClassActor *wpn = Net_ReadWeapon(stream); + PClassWeapon *wpn = Net_ReadWeapon(stream); players[player].weapons.AddSlot(slot, wpn, player == consoleplayer); } break; @@ -2400,7 +2400,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_ADDSLOTDEFAULT: { int slot = ReadByte(stream); - PClassActor *wpn = Net_ReadWeapon(stream); + PClassWeapon *wpn = Net_ReadWeapon(stream); players[player].weapons.AddSlotDefault(slot, wpn, player == consoleplayer); } break; diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index e31354a6e..608408627 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -169,9 +169,9 @@ int D_PlayerClassToInt (const char *classname) { for (unsigned int i = 0; i < PlayerClasses.Size (); ++i) { - const PClass *type = PlayerClasses[i].Type; + PClassPlayerPawn *type = PlayerClasses[i].Type; - if (stricmp (type->Meta.GetMetaString (APMETA_DisplayName), classname) == 0) + if (type->DisplayName.IsNotEmpty() && stricmp(type->DisplayName, classname) == 0) { return i; } @@ -556,7 +556,7 @@ void D_WriteUserInfoStrings (int i, BYTE **stream, bool compact) { userinfo_t *info = &players[i].userinfo; - const PClass *type = PlayerClasses[info->PlayerClass].Type; + PClassPlayerPawn *type = PlayerClasses[info->PlayerClass].Type; if (!compact) { @@ -582,8 +582,7 @@ void D_WriteUserInfoStrings (int i, BYTE **stream, bool compact) info->neverswitch, (float)(info->MoveBob) / 65536.f, (float)(info->StillBob) / 65536.f, - info->PlayerClass == -1 ? "Random" : - D_EscapeUserInfo(type->Meta.GetMetaString (APMETA_DisplayName)).GetChars() + info->PlayerClass == -1 ? "Random" : D_EscapeUserInfo(type->DisplayName).GetChars() ); } else @@ -611,8 +610,7 @@ void D_WriteUserInfoStrings (int i, BYTE **stream, bool compact) info->neverswitch, (float)(info->MoveBob) / 65536.f, (float)(info->StillBob) / 65536.f, - info->PlayerClass == -1 ? "Random" : - D_EscapeUserInfo(type->Meta.GetMetaString (APMETA_DisplayName)).GetChars() + info->PlayerClass == -1 ? "Random" : D_EscapeUserInfo(type->DisplayName).GetChars() ); } } @@ -837,7 +835,7 @@ CCMD (playerinfo) Printf ("MoveBob: %g\n", ui->MoveBob/65536.f); Printf ("StillBob: %g\n", ui->StillBob/65536.f); Printf ("PlayerClass: %s (%d)\n", - ui->PlayerClass == -1 ? "Random" : PlayerClasses[ui->PlayerClass].Type->Meta.GetMetaString (APMETA_DisplayName), + ui->PlayerClass == -1 ? "Random" : PlayerClasses[ui->PlayerClass].Type->DisplayName.GetChars(), ui->PlayerClass); if (argv.argc() > 2) PrintMiscActorInfo(players[i].mo); } diff --git a/src/d_player.h b/src/d_player.h index 3c9ad954c..75f0fbfa1 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -44,38 +44,30 @@ //Added by MC: #include "b_bot.h" -enum -{ - APMETA_BASE = 0x95000, - - APMETA_DisplayName, // display name (used in menus etc.) - APMETA_SoundClass, // sound class - APMETA_Face, // doom status bar face (when used) - APMETA_ColorRange, // skin color range - APMETA_InvulMode, - APMETA_HealingRadius, - APMETA_Hexenarmor0, - APMETA_Hexenarmor1, - APMETA_Hexenarmor2, - APMETA_Hexenarmor3, - APMETA_Hexenarmor4, - APMETA_Slot0, - APMETA_Slot1, - APMETA_Slot2, - APMETA_Slot3, - APMETA_Slot4, - APMETA_Slot5, - APMETA_Slot6, - APMETA_Slot7, - APMETA_Slot8, - APMETA_Slot9, -}; - class player_t; +class PClassPlayerPawn : public PClassActor +{ + DECLARE_CLASS(PClassPlayerPawn, PClassActor); +protected: + virtual void Derive(PClass *newclass); +public: + PClassPlayerPawn(); + + FString DisplayName; // Display name (used in menus, etc.) + FString SoundClass; // Sound class + FString Face; // Doom status bar face (when used) + FString Slot[10]; + FName InvulMode; + FName HealingRadiusType; + fixed_t HexenArmor[5]; + BYTE ColorRangeStart; // Skin color range + BYTE ColorRangeEnd; +}; + class APlayerPawn : public AActor { - DECLARE_CLASS (APlayerPawn, AActor) + DECLARE_CLASS_WITH_META(APlayerPawn, AActor, PClassPlayerPawn) HAS_OBJECT_POINTERS public: virtual void Serialize (FArchive &arc); @@ -431,7 +423,7 @@ public: bool CheckSkin (int skin); - const PClass *Type; + PClassPlayerPawn *Type; DWORD Flags; TArray<int> Skins; }; diff --git a/src/dobject.cpp b/src/dobject.cpp index f34a577bb..2f5fd0cac 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -60,134 +60,6 @@ ClassReg DObject::RegistrationInfo = }; _DECLARE_TI(DObject) -FMetaTable::~FMetaTable () -{ - FreeMeta (); -} - -FMetaTable::FMetaTable (const FMetaTable &other) -{ - Meta = NULL; - CopyMeta (&other); -} - -FMetaTable &FMetaTable::operator = (const FMetaTable &other) -{ - CopyMeta (&other); - return *this; -} - -void FMetaTable::FreeMeta () -{ - while (Meta != NULL) - { - FMetaData *meta = Meta; - - switch (meta->Type) - { - case META_String: - delete[] meta->Value.String; - break; - default: - break; - } - Meta = meta->Next; - delete meta; - } -} - -void FMetaTable::CopyMeta (const FMetaTable *other) -{ - const FMetaData *meta_src; - FMetaData **meta_dest; - - FreeMeta (); - - meta_src = other->Meta; - meta_dest = &Meta; - while (meta_src != NULL) - { - FMetaData *newmeta = new FMetaData (meta_src->Type, meta_src->ID); - switch (meta_src->Type) - { - case META_String: - newmeta->Value.String = copystring (meta_src->Value.String); - break; - default: - newmeta->Value = meta_src->Value; - break; - } - *meta_dest = newmeta; - meta_dest = &newmeta->Next; - meta_src = meta_src->Next; - } - *meta_dest = NULL; -} - -FMetaData *FMetaTable::FindMeta (EMetaType type, DWORD id) const -{ - FMetaData *meta = Meta; - - while (meta != NULL) - { - if (meta->ID == id && meta->Type == type) - { - return meta; - } - meta = meta->Next; - } - return NULL; -} - -FMetaData *FMetaTable::FindMetaDef (EMetaType type, DWORD id) -{ - FMetaData *meta = FindMeta (type, id); - if (meta == NULL) - { - meta = new FMetaData (type, id); - meta->Next = Meta; - meta->Value.String = NULL; - Meta = meta; - } - return meta; -} - -void FMetaTable::SetMetaInt (DWORD id, int parm) -{ - FMetaData *meta = FindMetaDef (META_Int, id); - meta->Value.Int = parm; -} - -int FMetaTable::GetMetaInt (DWORD id, int def) const -{ - FMetaData *meta = FindMeta (META_Int, id); - return meta != NULL ? meta->Value.Int : def; -} - -void FMetaTable::SetMetaFixed (DWORD id, fixed_t parm) -{ - FMetaData *meta = FindMetaDef (META_Fixed, id); - meta->Value.Fixed = parm; -} - -fixed_t FMetaTable::GetMetaFixed (DWORD id, fixed_t def) const -{ - FMetaData *meta = FindMeta (META_Fixed, id); - return meta != NULL ? meta->Value.Fixed : def; -} - -void FMetaTable::SetMetaString (DWORD id, const char *parm) -{ - FMetaData *meta = FindMetaDef (META_String, id); - ReplaceString (&meta->Value.String, parm); -} - -const char *FMetaTable::GetMetaString (DWORD id) const -{ - FMetaData *meta = FindMeta (META_String, id); - return meta != NULL ? meta->Value.String : NULL; -} - CCMD (dumpclasses) { // This is by no means speed-optimized. But it's an informational console diff --git a/src/dobject.h b/src/dobject.h index 5b6d99e46..23c284513 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -80,56 +80,6 @@ class DPillar; class PClassActor; -enum EMetaType -{ - META_Int, // An int - META_Fixed, // A fixed point number - META_String, // A string -}; - -class FMetaData -{ -private: - FMetaData (EMetaType type, uint32 id) : Type(type), ID(id) {} - - FMetaData *Next; - EMetaType Type; - uint32 ID; - union - { - int Int; - char *String; - fixed_t Fixed; - } Value; - - friend class FMetaTable; -}; - -class FMetaTable -{ -public: - FMetaTable() : Meta(NULL) {} - FMetaTable(const FMetaTable &other); - ~FMetaTable(); - FMetaTable &operator = (const FMetaTable &other); - - void SetMetaInt (uint32 id, int parm); - void SetMetaFixed (uint32 id, fixed_t parm); - void SetMetaString (uint32 id, const char *parm); // The string is copied - - int GetMetaInt (uint32 id, int def=0) const; - fixed_t GetMetaFixed (uint32 id, fixed_t def=0) const; - const char *GetMetaString (uint32 id) const; - - FMetaData *FindMeta (EMetaType type, uint32 id) const; - -private: - FMetaData *Meta; - FMetaData *FindMetaDef (EMetaType type, uint32 id); - void FreeMeta (); - void CopyMeta (const FMetaTable *other); -}; - #define RUNTIME_TYPE(object) (object->GetClass()) // Passed an object, returns the type of that object #define RUNTIME_CLASS_CASTLESS(cls) (cls::RegistrationInfo.MyClass) // Passed a native class name, returns a PClass representing that class #define RUNTIME_CLASS(cls) ((cls::MetaClass *)RUNTIME_CLASS_CASTLESS(cls)) // Like above, but returns the true type of the meta object @@ -140,6 +90,12 @@ enum { CLASSREG_PClass, CLASSREG_PClassActor, + CLASSREG_PClassInventory, + CLASSREG_PClassAmmo, + CLASSREG_PClassHealth, + CLASSREG_PClassPuzzleItem, + CLASSREG_PClassWeapon, + CLASSREG_PClassPlayerPawn }; struct ClassReg @@ -149,8 +105,8 @@ struct ClassReg ClassReg *ParentType; const size_t *Pointers; void (*ConstructNative)(void *); - unsigned int SizeOf:31; - unsigned int MetaClassNum:1; + unsigned int SizeOf:29; + unsigned int MetaClassNum:3; PClass *RegisterClass(); }; @@ -159,7 +115,7 @@ enum EInPlace { EC_InPlace }; #define DECLARE_ABSTRACT_CLASS(cls,parent) \ public: \ - virtual PClass *StaticType() const { return RegistrationInfo.MyClass; } \ + virtual PClass *StaticType() const; \ static ClassReg RegistrationInfo, * const RegistrationInfoPtr; \ private: \ typedef parent Super; \ @@ -205,7 +161,8 @@ protected: \ create, \ sizeof(cls), \ cls::MetaClassNum }; \ - _DECLARE_TI(cls) + _DECLARE_TI(cls) \ + PClass *cls::StaticType() const { return RegistrationInfo.MyClass; } #define _IMP_CREATE_OBJ(cls) \ void cls::InPlaceConstructor(void *mem) { new((EInPlace *)mem) cls; } diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index e0a4a0239..4e02dbba7 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -38,6 +38,8 @@ #include "templates.h" #include "autosegs.h" #include "v_text.h" +#include "a_pickups.h" +#include "d_player.h" IMPLEMENT_POINTY_CLASS(PClass) DECLARE_POINTER(ParentClass) @@ -121,6 +123,7 @@ PClass::PClass() Defaults = NULL; bRuntimeClass = false; ClassIndex = ~0; + ConstructNative = NULL; } PClass::~PClass() @@ -135,6 +138,18 @@ PClass::~PClass() PClass *ClassReg::RegisterClass() { + static ClassReg *const metaclasses[] = + { + &PClass::RegistrationInfo, + &PClassActor::RegistrationInfo, + &PClassInventory::RegistrationInfo, + &PClassAmmo::RegistrationInfo, + &PClassHealth::RegistrationInfo, + &PClassPuzzleItem::RegistrationInfo, + &PClassWeapon::RegistrationInfo, + &PClassPlayerPawn::RegistrationInfo, + }; + // MyClass may have already been created by a previous recursive call. // Or this may be a recursive call for a previously created class. if (MyClass != NULL) @@ -145,30 +160,35 @@ PClass *ClassReg::RegisterClass() // Add type to list PClass *cls; - switch (MetaClassNum) + if (MetaClassNum >= countof(metaclasses)) { - case CLASSREG_PClass: - cls = new PClass; - break; - - case CLASSREG_PClassActor: - cls = new PClassActor; - break; - - default: assert(0 && "Class registry has an invalid meta class identifier"); } + + if (this == &PClass::RegistrationInfo) + { + cls = new PClass; + } + else + { + if (metaclasses[MetaClassNum]->MyClass == NULL) + { // Make sure the meta class is already registered before registering this one + metaclasses[MetaClassNum]->RegisterClass(); + } + cls = static_cast<PClass *>(metaclasses[MetaClassNum]->MyClass->CreateNew()); + } + MyClass = cls; PClass::m_Types.Push(cls); cls->TypeName = FName(Name+1); - if (ParentType != NULL) - { - cls->ParentClass = ParentType->RegisterClass(); - } cls->Size = SizeOf; cls->Pointers = Pointers; cls->ConstructNative = ConstructNative; cls->InsertIntoHash(); + if (ParentType != NULL) + { + cls->ParentClass = ParentType->RegisterClass(); + } return cls; } @@ -231,7 +251,7 @@ PClass *PClass::FindClass (FName zaname) } // Create a new object that this class represents -DObject *PClass::CreateNew () const +DObject *PClass::CreateNew() const { BYTE *mem = (BYTE *)M_Malloc (Size); assert (mem != NULL); @@ -247,6 +267,23 @@ DObject *PClass::CreateNew () const return (DObject *)mem; } +// Copies inheritable values into the derived class and other miscellaneous setup. +void PClass::Derive(PClass *newclass) +{ + newclass->ParentClass = this; + newclass->ConstructNative = ConstructNative; + + // Set up default instance of the new class. + newclass->Defaults = (BYTE *)M_Malloc(newclass->Size); + memcpy(newclass->Defaults, Defaults, Size); + if (newclass->Size > Size) + { + memset(newclass->Defaults + Size, 0, newclass->Size - Size); + } + + newclass->Symbols.SetParentTable(&this->Symbols); +} + // Create a new class based on an existing class PClass *PClass::CreateDerivedClass (FName name, unsigned int size) { @@ -275,34 +312,16 @@ PClass *PClass::CreateDerivedClass (FName name, unsigned int size) } type->TypeName = name; - type->ParentClass = this; type->Size = size; - type->Pointers = NULL; - type->ConstructNative = ConstructNative; + type->bRuntimeClass = true; + Derive(type); if (!notnew) { type->ClassIndex = m_Types.Push (type); - } - type->Meta = Meta; - - // Set up default instance of the new class. - type->Defaults = (BYTE *)M_Malloc(size); - memcpy (type->Defaults, Defaults, Size); - if (size > Size) - { - memset (type->Defaults + Size, 0, size - Size); - } - - type->FlatPointers = NULL; - type->bRuntimeClass = true; - type->Symbols.SetParentTable (&this->Symbols); - if (!notnew) - { type->InsertIntoHash(); } - // If this class has an actor info, then any classes derived from it - // also need an actor info. + // If this class is for an actor, push it onto the RuntimeActors stack. if (type->IsKindOf(RUNTIME_CLASS(PClassActor))) { m_RuntimeActors.Push(static_cast<PClassActor *>(type)); @@ -351,17 +370,13 @@ PClass *PClass::FindClassTentative (FName name) break; } } - PClass *type = new PClassActor; + PClass *type = static_cast<PClass *>(GetClass()->CreateNew()); DPrintf("Creating placeholder class %s : %s\n", name.GetChars(), TypeName.GetChars()); type->TypeName = name; type->ParentClass = this; type->Size = -1; - type->Pointers = NULL; - type->ConstructNative = NULL; type->ClassIndex = m_Types.Push (type); - type->Defaults = NULL; - type->FlatPointers = NULL; type->bRuntimeClass = true; type->InsertIntoHash(); return type; diff --git a/src/dobjtype.h b/src/dobjtype.h index 091ec47ac..063c52a2c 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -153,6 +153,8 @@ class PClass : public DObject { DECLARE_CLASS(PClass, DObject); HAS_OBJECT_POINTERS; +protected: + virtual void Derive(PClass *newclass); public: static void StaticInit (); static void StaticShutdown (); @@ -164,7 +166,6 @@ public: const size_t *Pointers; // object pointers defined by this class *only* const size_t *FlatPointers; // object pointers defined by this class and all its superclasses; not initialized by default PClass *HashNext; - FMetaTable Meta; BYTE *Defaults; bool bRuntimeClass; // class was defined at run-time, not compile-time unsigned short ClassIndex; diff --git a/src/g_doom/a_bossbrain.cpp b/src/g_doom/a_bossbrain.cpp index 9e97f39dc..a91d5f0e9 100644 --- a/src/g_doom/a_bossbrain.cpp +++ b/src/g_doom/a_bossbrain.cpp @@ -180,8 +180,8 @@ static void SpawnFly(AActor *self, const PClass *spawntype, FSoundID sound) FName SpawnName; - FDropItem *di; // di will be our drop item list iterator - FDropItem *drop; // while drop stays as the reference point. + DDropItem *di; // di will be our drop item list iterator + DDropItem *drop; // while drop stays as the reference point. int n = 0; // First see if this cube has its own actor list @@ -197,11 +197,11 @@ static void SpawnFly(AActor *self, const PClass *spawntype, FSoundID sound) { if (di->Name != NAME_None) { - if (di->amount < 0) + if (di->Amount < 0) { - di->amount = 1; // default value is -1, we need a positive value. + di->Amount = 1; // default value is -1, we need a positive value. } - n += di->amount; // this is how we can weight the list. + n += di->Amount; // this is how we can weight the list. } } di = drop; @@ -210,7 +210,7 @@ static void SpawnFly(AActor *self, const PClass *spawntype, FSoundID sound) { if (di->Name != NAME_None) { - n -= di->amount; // logically, none of the -1 values have survived by now. + n -= di->Amount; // logically, none of the -1 values have survived by now. } if ((di->Next != NULL) && (n >= 0)) { diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index f7754fa86..a85af9dff 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -390,7 +390,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMissile) if (!weapon->DepleteAmmo (weapon->bAltFire)) return 0; } - P_SpawnPlayerMissile (self, PClass::FindClass("Rocket")); + P_SpawnPlayerMissile (self, PClass::FindActor("Rocket")); return 0; } @@ -452,7 +452,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePlasma) } } - P_SpawnPlayerMissile (self, PClass::FindClass("PlasmaBall")); + P_SpawnPlayerMissile (self, PClass::FindActor("PlasmaBall")); return 0; } @@ -537,7 +537,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireBFG) return 0; } - P_SpawnPlayerMissile (self, 0, 0, 0, PClass::FindClass("BFGBall"), self->angle, NULL, NULL, !!(dmflags2 & DF2_NO_FREEAIMBFG)); + P_SpawnPlayerMissile (self, 0, 0, 0, PClass::FindActor("BFGBall"), self->angle, NULL, NULL, !!(dmflags2 & DF2_NO_FREEAIMBFG)); return 0; } @@ -619,7 +619,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BFGsound) DEFINE_ACTION_FUNCTION(AActor, A_FireOldBFG) { PARAM_ACTION_PROLOGUE; - const PClass * plasma[] = {PClass::FindClass("PlasmaBall1"), PClass::FindClass("PlasmaBall2")}; + PClassActor *plasma[] = { PClass::FindActor("PlasmaBall1"), PClass::FindActor("PlasmaBall2") }; AActor * mo = NULL; player_t *player; diff --git a/src/g_doom/a_revenant.cpp b/src/g_doom/a_revenant.cpp index b03106892..4d78f359f 100644 --- a/src/g_doom/a_revenant.cpp +++ b/src/g_doom/a_revenant.cpp @@ -65,7 +65,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer) return 0; // spawn a puff of smoke behind the rocket - P_SpawnPuff (self, PClass::FindClass(NAME_BulletPuff), self->x, self->y, self->z, 0, 3); + P_SpawnPuff (self, PClass::FindActor(NAME_BulletPuff), self->x, self->y, self->z, 0, 3); smoke = Spawn ("RevenantTracerSmoke", self->x - self->velx, self->y - self->vely, self->z, ALLOW_REPLACE); diff --git a/src/g_heretic/a_dsparil.cpp b/src/g_heretic/a_dsparil.cpp index 8ec664d84..4e1e0edfc 100644 --- a/src/g_heretic/a_dsparil.cpp +++ b/src/g_heretic/a_dsparil.cpp @@ -83,7 +83,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Srcr1Attack) return 0; } - const PClass *fx = PClass::FindClass("SorcererFX1"); + PClassActor *fx = PClass::FindActor("SorcererFX1"); if (self->health > (self->SpawnHealth()/3)*2) { // Spit one fireball P_SpawnMissileZ (self, self->z + 48*FRACUNIT, self->target, fx ); @@ -225,7 +225,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Srcr2Attack) if (pr_s2a() < chance) { // Wizard spawners - const PClass *fx = PClass::FindClass("Sorcerer2FX2"); + PClassActor *fx = PClass::FindActor("Sorcerer2FX2"); if (fx) { P_SpawnMissileAngle (self, fx, self->angle-ANG45, FRACUNIT/2); @@ -234,7 +234,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Srcr2Attack) } else { // Blue bolt - P_SpawnMissile (self, self->target, PClass::FindClass("Sorcerer2FX1")); + P_SpawnMissile (self, self->target, PClass::FindActor("Sorcerer2FX1")); } return 0; } diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index ec1a052e1..fface239b 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -168,8 +168,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireGoldWandPL2) angle_t pitch = P_BulletSlope(self); velz = FixedMul (GetDefaultByName("GoldWandFX2")->Speed, finetangent[FINEANGLES/4-((signed)pitch>>ANGLETOFINESHIFT)]); - P_SpawnMissileAngle (self, PClass::FindClass("GoldWandFX2"), self->angle-(ANG45/8), velz); - P_SpawnMissileAngle (self, PClass::FindClass("GoldWandFX2"), self->angle+(ANG45/8), velz); + P_SpawnMissileAngle (self, PClass::FindActor("GoldWandFX2"), self->angle-(ANG45/8), velz); + P_SpawnMissileAngle (self, PClass::FindActor("GoldWandFX2"), self->angle+(ANG45/8), velz); angle = self->angle-(ANG45/8); for(i = 0; i < 5; i++) { @@ -204,9 +204,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireCrossbowPL1) if (!weapon->DepleteAmmo (weapon->bAltFire)) return 0; } - P_SpawnPlayerMissile (self, PClass::FindClass("CrossbowFX1")); - P_SpawnPlayerMissile (self, PClass::FindClass("CrossbowFX3"), self->angle-(ANG45/10)); - P_SpawnPlayerMissile (self, PClass::FindClass("CrossbowFX3"), self->angle+(ANG45/10)); + P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX1")); + P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX3"), self->angle-(ANG45/10)); + P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX3"), self->angle+(ANG45/10)); return 0; } @@ -233,11 +233,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireCrossbowPL2) if (!weapon->DepleteAmmo (weapon->bAltFire)) return 0; } - P_SpawnPlayerMissile (self, PClass::FindClass("CrossbowFX2")); - P_SpawnPlayerMissile (self, PClass::FindClass("CrossbowFX2"), self->angle-(ANG45/10)); - P_SpawnPlayerMissile (self, PClass::FindClass("CrossbowFX2"), self->angle+(ANG45/10)); - P_SpawnPlayerMissile (self, PClass::FindClass("CrossbowFX3"), self->angle-(ANG45/5)); - P_SpawnPlayerMissile (self, PClass::FindClass("CrossbowFX3"), self->angle+(ANG45/5)); + P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX2")); + P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX2"), self->angle-(ANG45/10)); + P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX2"), self->angle+(ANG45/10)); + P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX3"), self->angle-(ANG45/5)); + P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX3"), self->angle+(ANG45/5)); return 0; } @@ -448,7 +448,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMacePL1) } player->psprites[ps_weapon].sx = ((pr_maceatk()&3)-2)*FRACUNIT; player->psprites[ps_weapon].sy = WEAPONTOP+(pr_maceatk()&3)*FRACUNIT; - ball = P_SpawnPlayerMissile (self, PClass::FindClass("MaceFX1"), + ball = P_SpawnPlayerMissile (self, PClass::FindActor("MaceFX1"), self->angle+(((pr_maceatk()&7)-4)<<24)); if (ball) { @@ -942,7 +942,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSkullRodPL1) if (!weapon->DepleteAmmo (weapon->bAltFire)) return 0; } - mo = P_SpawnPlayerMissile (self, PClass::FindClass("HornRodFX1")); + mo = P_SpawnPlayerMissile (self, PClass::FindActor("HornRodFX1")); // Randomize the first frame if (mo && pr_fsr1() > 128) { diff --git a/src/g_heretic/a_wizard.cpp b/src/g_heretic/a_wizard.cpp index 69611546d..458cb8afe 100644 --- a/src/g_heretic/a_wizard.cpp +++ b/src/g_heretic/a_wizard.cpp @@ -84,7 +84,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_WizAtk3) P_TraceBleed (damage, self->target, self); return 0; } - const PClass *fx = PClass::FindClass("WizardFX1"); + PClassActor *fx = PClass::FindActor("WizardFX1"); mo = P_SpawnMissile (self, self->target, fx); if (mo != NULL) { diff --git a/src/g_hexen/a_bats.cpp b/src/g_hexen/a_bats.cpp index c6d0389d9..d00422837 100644 --- a/src/g_hexen/a_bats.cpp +++ b/src/g_hexen/a_bats.cpp @@ -48,7 +48,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BatSpawn) delta = self->args[1]; if (delta==0) delta=1; angle = self->angle + (((pr_batspawn()%delta)-(delta>>1))<<24); - mo = P_SpawnMissileAngle (self, PClass::FindClass ("Bat"), angle, 0); + mo = P_SpawnMissileAngle (self, PClass::FindActor("Bat"), angle, 0); if (mo) { mo->args[0] = pr_batspawn()&63; // floatbob index diff --git a/src/g_hexen/a_clericholy.cpp b/src/g_hexen/a_clericholy.cpp index 9cf1a79ad..d9171dc8b 100644 --- a/src/g_hexen/a_clericholy.cpp +++ b/src/g_hexen/a_clericholy.cpp @@ -249,8 +249,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolyAttack) if (!weapon->DepleteAmmo (weapon->bAltFire)) return 0; } - AActor * missile = P_SpawnPlayerMissile (self, 0,0,0, PClass::FindClass ("HolyMissile"), self->angle, &linetarget); - if (missile != NULL) missile->tracer = linetarget; + AActor *missile = P_SpawnPlayerMissile (self, 0,0,0, PClass::FindActor("HolyMissile"), self->angle, &linetarget); + if (missile != NULL) + { + missile->tracer = linetarget; + } weapon->CHolyCount = 3; S_Sound (self, CHAN_WEAPON, "HolySymbolFire", 1, ATTN_NORM); diff --git a/src/g_hexen/a_fighterhammer.cpp b/src/g_hexen/a_fighterhammer.cpp index 2eb226f2a..e0dca5068 100644 --- a/src/g_hexen/a_fighterhammer.cpp +++ b/src/g_hexen/a_fighterhammer.cpp @@ -126,7 +126,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerThrow) if (!weapon->DepleteAmmo (weapon->bAltFire, false)) return 0; } - mo = P_SpawnPlayerMissile (player->mo, PClass::FindClass ("HammerMissile")); + mo = P_SpawnPlayerMissile (player->mo, PClass::FindActor("HammerMissile")); if (mo) { mo->special1 = 0; diff --git a/src/g_hexen/a_healingradius.cpp b/src/g_hexen/a_healingradius.cpp index b827f666b..a18116dac 100644 --- a/src/g_hexen/a_healingradius.cpp +++ b/src/g_hexen/a_healingradius.cpp @@ -30,7 +30,12 @@ IMPLEMENT_CLASS (AArtiHealingRadius) bool AArtiHealingRadius::Use (bool pickup) { bool effective = false; - int mode = Owner->GetClass()->Meta.GetMetaInt(APMETA_HealingRadius); + FName mode; + + if (Owner->IsKindOf(RUNTIME_CLASS(APlayerPawn))) + { + mode = static_cast<PClassPlayerPawn *>(Owner->GetClass())->HealingRadiusType; + } for (int i = 0; i < MAXPLAYERS; ++i) { diff --git a/src/g_hexen/a_heresiarch.cpp b/src/g_hexen/a_heresiarch.cpp index ecb27b5ed..62cecea14 100644 --- a/src/g_hexen/a_heresiarch.cpp +++ b/src/g_hexen/a_heresiarch.cpp @@ -574,7 +574,7 @@ void ASorcBall3::CastSorcererSpell () ang1 = angle - ANGLE_45; ang2 = angle + ANGLE_45; - const PClass *cls = PClass::FindClass("SorcFX3"); + PClassActor *cls = PClass::FindActor("SorcFX3"); if (health < (SpawnHealth()/3)) { // Spawn 2 at a time mo = P_SpawnMissileAngle(parent, cls, ang1, 4*FRACUNIT); @@ -623,7 +623,7 @@ void ASorcBall1::CastSorcererSpell () ang1 = angle + ANGLE_1*70; ang2 = angle - ANGLE_1*70; - const PClass *cls = PClass::FindClass("SorcFX1"); + PClassActor *cls = PClass::FindActor("SorcFX1"); mo = P_SpawnMissileAngle (parent, cls, ang1, 0); if (mo) { @@ -670,7 +670,7 @@ void A_SorcOffense2(AActor *actor) delta = (finesine[index])*SORCFX4_SPREAD_ANGLE; delta = (delta>>FRACBITS)*ANGLE_1; ang1 = actor->angle + delta; - mo = P_SpawnMissileAngle(parent, PClass::FindClass("SorcFX4"), ang1, 0); + mo = P_SpawnMissileAngle(parent, PClass::FindActor("SorcFX4"), ang1, 0); if (mo) { mo->special2 = 35*5/2; // 5 seconds diff --git a/src/g_hexen/a_iceguy.cpp b/src/g_hexen/a_iceguy.cpp index f43a76122..e4a501443 100644 --- a/src/g_hexen/a_iceguy.cpp +++ b/src/g_hexen/a_iceguy.cpp @@ -144,7 +144,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceGuyMissileExplode) for (i = 0; i < 8; i++) { mo = P_SpawnMissileAngleZ (self, self->z+3*FRACUNIT, - PClass::FindClass("IceGuyFX2"), i*ANG45, (fixed_t)(-0.3*FRACUNIT)); + PClass::FindActor("IceGuyFX2"), i*ANG45, (fixed_t)(-0.3*FRACUNIT)); if (mo) { mo->target = self->target; diff --git a/src/g_hexen/a_korax.cpp b/src/g_hexen/a_korax.cpp index a1f729865..d0509c408 100644 --- a/src/g_hexen/a_korax.cpp +++ b/src/g_hexen/a_korax.cpp @@ -164,8 +164,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxBonePop) // Spawn 6 spirits equalangularly for (i = 0; i < 6; ++i) { - mo = P_SpawnMissileAngle (self, PClass::FindClass("KoraxSpirit"), ANGLE_60*i, 5*FRACUNIT); - if (mo) KSpiritInit (mo, self); + mo = P_SpawnMissileAngle (self, PClass::FindActor("KoraxSpirit"), ANGLE_60*i, 5*FRACUNIT); + if (mo) + { + KSpiritInit (mo, self); + } } P_StartScript (self, NULL, 255, NULL, 0, 0, 0, 0, false, false); // Death script diff --git a/src/g_hexen/a_magelightning.cpp b/src/g_hexen/a_magelightning.cpp index 5d9880a40..7010aaceb 100644 --- a/src/g_hexen/a_magelightning.cpp +++ b/src/g_hexen/a_magelightning.cpp @@ -215,10 +215,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightningZap) { PARAM_ACTION_PROLOGUE; - const PClass *lightning=PClass::FindClass((ENamedName) self->GetClass()->Meta.GetMetaInt (ACMETA_MissileName, NAME_LightningZap)); + PClassActor *lightning = PClass::FindActor(self->GetClass()->MissileName); AActor *mo; fixed_t deltaZ; + if (lightning == NULL) + { + lightning = PClass::FindActor(NAME_LightningZap); + } + CALL_ACTION(A_LightningClip, self); self->health -= 8; @@ -338,10 +343,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_ZapMimic) DEFINE_ACTION_FUNCTION(AActor, A_LastZap) { PARAM_ACTION_PROLOGUE; - const PClass *lightning=PClass::FindClass((ENamedName) self->GetClass()->Meta.GetMetaInt (ACMETA_MissileName, NAME_LightningZap)); + PClassActor *lightning = PClass::FindActor(self->GetClass()->MissileName); AActor *mo; + if (lightning == NULL) + { + lightning = PClass::FindActor(NAME_LightningZap); + } mo = Spawn(lightning, self->x, self->y, self->z, ALLOW_REPLACE); if (mo) { diff --git a/src/g_hexen/a_summon.cpp b/src/g_hexen/a_summon.cpp index 6f698cbc2..14f0e4b7f 100644 --- a/src/g_hexen/a_summon.cpp +++ b/src/g_hexen/a_summon.cpp @@ -31,7 +31,7 @@ IMPLEMENT_CLASS (AArtiDarkServant) bool AArtiDarkServant::Use (bool pickup) { - AActor *mo = P_SpawnPlayerMissile (Owner, PClass::FindClass ("SummoningDoll")); + AActor *mo = P_SpawnPlayerMissile (Owner, PClass::FindActor("SummoningDoll")); if (mo) { mo->target = Owner; diff --git a/src/g_raven/a_minotaur.cpp b/src/g_raven/a_minotaur.cpp index cb51a32d0..138ef59f6 100644 --- a/src/g_raven/a_minotaur.cpp +++ b/src/g_raven/a_minotaur.cpp @@ -301,7 +301,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk2) return 0; } z = self->z + 40*FRACUNIT; - const PClass *fx = PClass::FindClass("MinotaurFX1"); + PClassActor *fx = PClass::FindActor("MinotaurFX1"); if (fx) { mo = P_SpawnMissileZ (self, z, self->target, fx); diff --git a/src/g_shared/a_action.cpp b/src/g_shared/a_action.cpp index 4c007ad17..abaaa4e3e 100644 --- a/src/g_shared/a_action.cpp +++ b/src/g_shared/a_action.cpp @@ -83,7 +83,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_NoBlocking) // If the self has attached metadata for items to drop, drop those. if (!self->IsKindOf (RUNTIME_CLASS (APlayerPawn))) // [GRB] { - FDropItem *di = self->GetDropItems(); + DDropItem *di = self->GetDropItems(); if (di != NULL) { @@ -92,7 +92,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_NoBlocking) if (di->Name != NAME_None) { const PClass *ti = PClass::FindClass(di->Name); - if (ti) P_DropItem (self, ti, di->amount, di->probability); + if (ti) P_DropItem (self, ti, di->Amount, di->Probability); } di = di->Next; } diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index ec49b683d..0dcfac57c 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -349,9 +349,9 @@ void APowerInvulnerable::InitEffect () { Owner->effects &= ~FX_RESPAWNINVUL; Owner->flags2 |= MF2_INVULNERABLE; - if (Mode == NAME_None) + if (Mode == NAME_None && Owner->IsKindOf(RUNTIME_CLASS(APlayerPawn))) { - Mode = (ENamedName)RUNTIME_TYPE(Owner)->Meta.GetMetaInt(APMETA_InvulMode); + Mode = static_cast<PClassPlayerPawn *>(Owner->GetClass())->InvulMode; } if (Mode == NAME_Reflective) { @@ -1729,7 +1729,7 @@ void APowerMorph::InitEffect( ) player_t *realplayer = Owner->player; // Remember the identity of the player const PClass *morph_flash = PClass::FindClass (MorphFlash); const PClass *unmorph_flash = PClass::FindClass (UnMorphFlash); - const PClass *player_class = PClass::FindClass (PlayerClass); + PClassPlayerPawn *player_class = dyn_cast<PClassPlayerPawn>(PClass::FindClass (PlayerClass)); if (P_MorphPlayer(realplayer, realplayer, player_class, -1/*INDEFINITELY*/, MorphStyle, morph_flash, unmorph_flash)) { Owner = realplayer->mo; // Replace the new owner in our owner; safe because we are not attached to anything yet diff --git a/src/g_shared/a_fastprojectile.cpp b/src/g_shared/a_fastprojectile.cpp index 3bd2903ee..614985234 100644 --- a/src/g_shared/a_fastprojectile.cpp +++ b/src/g_shared/a_fastprojectile.cpp @@ -154,7 +154,7 @@ void AFastProjectile::Effect() { //if (pr_smoke() < 128) // [RH] I think it looks better if it's consistent { - FName name = (ENamedName) this->GetClass()->Meta.GetMetaInt (ACMETA_MissileName, NAME_None); + FName name = GetClass()->MissileName; if (name != NAME_None) { fixed_t hitz = z-8*FRACUNIT; diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 7cbfbc5ad..70f79b3a0 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -25,7 +25,7 @@ static FRandom pr_morphmonst ("MorphMonster"); // //--------------------------------------------------------------------------- -bool P_MorphPlayer (player_t *activator, player_t *p, const PClass *spawntype, int duration, int style, const PClass *enter_flash, const PClass *exit_flash) +bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntype, int duration, int style, const PClass *enter_flash, const PClass *exit_flash) { AInventory *item; APlayerPawn *morphed; @@ -129,7 +129,7 @@ bool P_MorphPlayer (player_t *activator, player_t *p, const PClass *spawntype, i hxarmor->Slots[1] = 0; hxarmor->Slots[2] = 0; hxarmor->Slots[3] = 0; - hxarmor->Slots[4] = spawntype->Meta.GetMetaFixed (APMETA_Hexenarmor0); + hxarmor->Slots[4] = spawntype->HexenArmor[0]; } else if (item->ItemFlags & IF_KEEPDEPLETED) { @@ -157,9 +157,7 @@ bool P_MorphPlayer (player_t *activator, player_t *p, const PClass *spawntype, i // and for the original DOOM status bar. if (p == &players[consoleplayer]) { - const char *face = spawntype->Meta.GetMetaString (APMETA_Face); - - if (face != NULL && strcmp(face, "None") != 0) + if (spawntype->Face.IsNotEmpty() && strcmp(spawntype->Face, "None") != 0) { StatusBar->SetFace(&skins[p->MorphedPlayerClass]); } @@ -285,8 +283,8 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, // and for the original DOOM status bar. if ((player == &players[consoleplayer])) { - const char *face = pmo->GetClass()->Meta.GetMetaString (APMETA_Face); - if (face != NULL && strcmp(face, "None") != 0) + FString face = pmo->GetClass()->Face; + if (face.IsNotEmpty() && strcmp(face, "None") != 0) { // Assume root-level base skin to begin with size_t skinindex = 0; @@ -361,7 +359,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, AHexenArmor *hxarmor = mo->FindInventory<AHexenArmor>(); if (hxarmor != NULL) { - hxarmor->Slots[4] = mo->GetClass()->Meta.GetMetaFixed (APMETA_Hexenarmor0); + hxarmor->Slots[4] = mo->GetClass()->HexenArmor[0]; } return true; } @@ -558,7 +556,7 @@ int AMorphProjectile::DoSpecialDamage (AActor *target, int damage) const PClass *unmorph_flash = PClass::FindClass (UnMorphFlash); if (target->player) { - const PClass *player_class = PClass::FindClass (PlayerClass); + PClassPlayerPawn *player_class = dyn_cast<PClassPlayerPawn>(PClass::FindClass(PlayerClass)); P_MorphPlayer (NULL, target->player, player_class, Duration, MorphStyle, morph_flash, unmorph_flash); } else diff --git a/src/g_shared/a_morph.h b/src/g_shared/a_morph.h index 891fe619b..8ea90bf5d 100644 --- a/src/g_shared/a_morph.h +++ b/src/g_shared/a_morph.h @@ -33,7 +33,7 @@ class AActor; class player_t; class AMorphedMonster; -bool P_MorphPlayer (player_t *activator, player_t *player, const PClass *morphclass, int duration = 0, int style = 0, +bool P_MorphPlayer (player_t *activator, player_t *player, PClassPlayerPawn *morphclass, int duration = 0, int style = 0, const PClass *enter_flash = NULL, const PClass *exit_flash = NULL); bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag = 0, bool force = false); bool P_MorphMonster (AActor *actor, const PClass *morphclass, int duration = 0, int style = 0, diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index eb7a25425..b64eaafea 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -20,6 +20,41 @@ static FRandom pr_restore ("RestorePos"); +IMPLEMENT_CLASS(PClassInventory) + +PClassInventory::PClassInventory() +{ + GiveQuest = 0; + AltHUDIcon.SetInvalid(); +} + +void PClassInventory::Derive(PClass *newclass) +{ + assert(newclass->IsKindOf(RUNTIME_CLASS(PClassInventory))); + Super::Derive(newclass); + PClassInventory *newc = static_cast<PClassInventory *>(newclass); + + newc->PickupMessage = PickupMessage; + newc->GiveQuest = GiveQuest; + newc->AltHUDIcon = AltHUDIcon; +} + +IMPLEMENT_CLASS(PClassAmmo) + +PClassAmmo::PClassAmmo() +{ + DropAmount = 0; +} + +void PClassAmmo::Derive(PClass *newclass) +{ + assert(newclass->IsKindOf(RUNTIME_CLASS(PClassAmmo))); + Super::Derive(newclass); + PClassAmmo *newc = static_cast<PClassAmmo *>(newclass); + + newc->DropAmount = DropAmount; +} + IMPLEMENT_CLASS (AAmmo) //=========================================================================== @@ -970,9 +1005,9 @@ void AInventory::DoPickupSpecial (AActor *toucher) const char *AInventory::PickupMessage () { - const char *message = GetClass()->Meta.GetMetaString (AIMETA_PickupMessage); + FString message = GetClass()->PickupMessage; - return message != NULL? message : "You got a pickup"; + return message.IsNotEmpty() ? message : "You got a pickup"; } //=========================================================================== @@ -1169,8 +1204,8 @@ bool AInventory::DoRespawn () void AInventory::GiveQuest (AActor *toucher) { - int quest = GetClass()->Meta.GetMetaInt(AIMETA_GiveQuest); - if (quest>0 && quest<31) + int quest = GetClass()->GiveQuest; + if (quest > 0 && quest <= countof(QuestItemClasses)) { toucher->GiveInventoryType (QuestItemClasses[quest-1]); } @@ -1394,6 +1429,35 @@ bool ACustomInventory::TryPickup (AActor *&toucher) return useok; } +IMPLEMENT_CLASS(PClassHealth) + +//=========================================================================== +// +// PClassHealth Constructor +// +//=========================================================================== + +PClassHealth::PClassHealth() +{ + LowHealth = 0; +} + +//=========================================================================== +// +// PClassHealth :: Derive +// +//=========================================================================== + +void PClassHealth::Derive(PClass *newclass) +{ + assert(newclass->IsKindOf(RUNTIME_CLASS(PClassHealth))); + Super::Derive(newclass); + PClassHealth *newc = static_cast<PClassHealth *>(newclass); + + newc->LowHealth = LowHealth; + newc->LowHealthMessage = LowHealthMessage; +} + IMPLEMENT_CLASS (AHealth) //=========================================================================== @@ -1403,13 +1467,13 @@ IMPLEMENT_CLASS (AHealth) //=========================================================================== const char *AHealth::PickupMessage () { - int threshold = GetClass()->Meta.GetMetaInt(AIMETA_LowHealth, 0); + int threshold = GetClass()->LowHealth; if (PrevHealth < threshold) { - const char *message = GetClass()->Meta.GetMetaString (AIMETA_LowHealthMessage); + FString message = GetClass()->LowHealthMessage; - if (message != NULL) + if (message.IsNotEmpty()) { return message; } diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 0e531066f..06f21c8e9 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -10,6 +10,8 @@ class player_t; class FConfigFile; class AWeapon; +class PClassWeapon; +class PClassPlayerPawn; class FWeaponSlot { @@ -19,13 +21,13 @@ public: FWeaponSlot &operator= (const FWeaponSlot &other) { Weapons = other.Weapons; return *this; } void Clear() { Weapons.Clear(); } bool AddWeapon (const char *type); - bool AddWeapon (PClassActor *type); + bool AddWeapon (PClassWeapon *type); void AddWeaponList (const char *list, bool clear); AWeapon *PickWeapon (player_t *player); int Size () const { return (int)Weapons.Size(); } - int LocateWeapon (PClassActor *type); + int LocateWeapon (PClassWeapon *type); - inline PClassActor *GetWeapon (int index) const + inline PClassWeapon *GetWeapon (int index) const { if ((unsigned)index < Weapons.Size()) { @@ -42,7 +44,7 @@ public: private: struct WeaponInfo { - PClassActor *Type; + PClassWeapon *Type; fixed_t Position; }; void SetInitialPositions(); @@ -68,25 +70,25 @@ struct FWeaponSlots AWeapon *PickPrevWeapon (player_t *player); void Clear (); - bool LocateWeapon (PClassActor *type, int *const slot, int *const index); - ESlotDef AddDefaultWeapon (int slot, PClassActor *type); + bool LocateWeapon (PClassWeapon *type, int *const slot, int *const index); + ESlotDef AddDefaultWeapon (int slot, PClassWeapon *type); void AddExtraWeapons(); void SetFromGameInfo(); - void SetFromPlayer(PClassActor *type); - void StandardSetup(PClassActor *type); + void SetFromPlayer(PClassPlayerPawn *type); + void StandardSetup(PClassPlayerPawn *type); void LocalSetup(PClassActor *type); void SendDifferences(const FWeaponSlots &other); int RestoreSlots (FConfigFile *config, const char *section); void PrintSettings(); - void AddSlot(int slot, PClassActor *type, bool feedback); - void AddSlotDefault(int slot, PClassActor *type, bool feedback); + void AddSlot(int slot, PClassWeapon *type, bool feedback); + void AddSlotDefault(int slot, PClassWeapon *type, bool feedback); }; void P_PlaybackKeyConfWeapons(FWeaponSlots *slots); -void Net_WriteWeapon(PClassActor *type); -PClassActor *Net_ReadWeapon(BYTE **stream); +void Net_WriteWeapon(PClassWeapon *type); +PClassWeapon *Net_ReadWeapon(BYTE **stream); void P_SetupWeapons_ntohton(); void P_WriteDemoWeaponsChunk(BYTE **demo); @@ -98,17 +100,6 @@ void P_ReadDemoWeaponsChunk(BYTE **demo); // A pickup is anything the player can pickup (i.e. weapons, ammo, powerups, etc) -enum -{ - AIMETA_BASE = 0x71000, - AIMETA_PickupMessage, // string - AIMETA_GiveQuest, // optionally give one of the quest items. - AIMETA_DropAmount, // specifies the amount for a dropped ammo item - AIMETA_LowHealth, - AIMETA_LowHealthMessage, - AIMETA_PuzzFailMessage, -}; - enum { IF_ACTIVATABLE = 1<<0, // can be activated @@ -134,9 +125,22 @@ enum struct vissprite_t; +class PClassInventory : public PClassActor +{ + DECLARE_CLASS(PClassInventory, PClassActor) +protected: + virtual void Derive(PClass *newclass); +public: + PClassInventory(); + + FString PickupMessage; + int GiveQuest; // Optionally give one of the quest items. + FTextureID AltHUDIcon; +}; + class AInventory : public AActor { - DECLARE_CLASS (AInventory, AActor) + DECLARE_CLASS_WITH_META(AInventory, AActor, PClassInventory) HAS_OBJECT_POINTERS public: virtual void Touch (AActor *toucher); @@ -172,7 +176,7 @@ public: const PClass *SpawnPointClass; // For respawning like Heretic's mace DWORD ItemFlags; - const PClass *PickupFlash; // actor to spawn as pickup flash + PClassActor *PickupFlash; // actor to spawn as pickup flash FSoundIDNoInit PickupSound; @@ -220,9 +224,20 @@ public: }; // Ammo: Something a weapon needs to operate +class PClassAmmo : public PClassInventory +{ + DECLARE_CLASS(PClassAmmo, PClassInventory) +protected: + virtual void Derive(PClass *newclass); +public: + PClassAmmo(); + + int DropAmount; // Specifies the amount for a dropped ammo item. +}; + class AAmmo : public AInventory { - DECLARE_CLASS (AAmmo, AInventory) + DECLARE_CLASS_WITH_META(AAmmo, AInventory, PClassAmmo) public: void Serialize (FArchive &arc); AInventory *CreateCopy (AActor *other); @@ -234,27 +249,32 @@ public: }; // A weapon is just that. -enum +class PClassWeapon : public PClassInventory { - AWMETA_BASE = 0x72000, - AWMETA_SlotNumber, - AWMETA_SlotPriority, + DECLARE_CLASS(PClassWeapon, PClassInventory); +protected: + virtual void Derive(PClass *newclass); +public: + PClassWeapon(); + + int SlotNumber; + fixed_t SlotPriority; }; class AWeapon : public AInventory { - DECLARE_CLASS (AWeapon, AInventory) + DECLARE_CLASS_WITH_META(AWeapon, AInventory, PClassWeapon) HAS_OBJECT_POINTERS public: DWORD WeaponFlags; - PClassActor *AmmoType1, *AmmoType2; // Types of ammo used by this weapon + PClassAmmo *AmmoType1, *AmmoType2; // Types of ammo used by this weapon int AmmoGive1, AmmoGive2; // Amount of each ammo to get when picking up weapon int MinAmmo1, MinAmmo2; // Minimum ammo needed to switch to this weapon int AmmoUse1, AmmoUse2; // How much ammo to use with each shot int Kickback; fixed_t YAdjust; // For viewing the weapon fullscreen FSoundIDNoInit UpSound, ReadySound; // Sounds when coming up and idle - PClassActor *SisterWeaponType; // Another weapon to pick up with this one + PClassWeapon *SisterWeaponType; // Another weapon to pick up with this one PClassActor *ProjectileType; // Projectile used by primary attack PClassActor *AltProjectileType; // Projectile used by alternate attack int SelectionOrder; // Lower-numbered weapons get picked first @@ -302,7 +322,7 @@ public: protected: AAmmo *AddAmmo (AActor *other, PClassActor *ammotype, int amount); bool AddExistingAmmo (AAmmo *ammo, int amount); - AWeapon *AddWeapon (PClassActor *weapon); + AWeapon *AddWeapon (PClassWeapon *weapon); }; enum @@ -336,9 +356,21 @@ enum #define S_LIGHTDONE 0 // Health is some item that gives the player health when picked up. +class PClassHealth : public PClassInventory +{ + DECLARE_CLASS(PClassHealth, PClassInventory) +protected: + virtual void Derive(PClass *newclass); +public: + PClassHealth(); + + FString LowHealthMessage; + int LowHealth; +}; + class AHealth : public AInventory { - DECLARE_CLASS (AHealth, AInventory) + DECLARE_CLASS_WITH_META(AHealth, AInventory, PClassHealth) int PrevHealth; public: @@ -440,9 +472,18 @@ protected: }; // PuzzleItems work in conjunction with the UsePuzzleItem special +class PClassPuzzleItem : public PClassInventory +{ + DECLARE_CLASS(PClassPuzzleItem, PClassInventory); +protected: + virtual void Derive(PClass *newclass); +public: + FString PuzzFailMessage; +}; + class APuzzleItem : public AInventory { - DECLARE_CLASS (APuzzleItem, AInventory) + DECLARE_CLASS_WITH_META(APuzzleItem, AInventory, PClassPuzzleItem) public: void Serialize (FArchive &arc); bool ShouldStay (); diff --git a/src/g_shared/a_puzzleitems.cpp b/src/g_shared/a_puzzleitems.cpp index 0cbc7cc33..c32e03761 100644 --- a/src/g_shared/a_puzzleitems.cpp +++ b/src/g_shared/a_puzzleitems.cpp @@ -8,7 +8,16 @@ #include "doomstat.h" #include "v_font.h" -IMPLEMENT_CLASS (APuzzleItem) +IMPLEMENT_CLASS(PClassPuzzleItem) + +void PClassPuzzleItem::Derive(PClass *newclass) +{ + Super::Derive(newclass); + assert(newclass->IsKindOf(RUNTIME_CLASS(PClassPuzzleItem))); + static_cast<PClassPuzzleItem *>(newclass)->PuzzFailMessage = PuzzFailMessage; +} + +IMPLEMENT_CLASS(APuzzleItem) void APuzzleItem::Serialize (FArchive &arc) { @@ -36,9 +45,9 @@ bool APuzzleItem::Use (bool pickup) S_Sound (Owner, CHAN_VOICE, "*puzzfail", 1, ATTN_IDLE); if (Owner != NULL && Owner->CheckLocalView (consoleplayer)) { - const char *message = GetClass()->Meta.GetMetaString (AIMETA_PuzzFailMessage); - if (message != NULL && *message=='$') message = GStrings[message + 1]; - if (message == NULL) message = GStrings("TXT_USEPUZZLEFAILED"); + FString message = GetClass()->PuzzFailMessage; + if (message.IsNotEmpty() && message[0] == '$') message = GStrings[&message[1]]; + if (message.IsEmpty()) message = GStrings("TXT_USEPUZZLEFAILED"); C_MidPrintBold (SmallFont, message); } return false; diff --git a/src/g_shared/a_randomspawner.cpp b/src/g_shared/a_randomspawner.cpp index 026788e78..48e21e791 100644 --- a/src/g_shared/a_randomspawner.cpp +++ b/src/g_shared/a_randomspawner.cpp @@ -28,9 +28,9 @@ class ARandomSpawner : public AActor // random spawner's velocity (0...) instead of their own. void BeginPlay() { - FDropItem *di; // di will be our drop item list iterator - FDropItem *drop; // while drop stays as the reference point. - int n=0; + DDropItem *di; // di will be our drop item list iterator + DDropItem *drop; // while drop stays as the reference point. + int n = 0; Super::BeginPlay(); drop = di = GetDropItems(); @@ -40,8 +40,8 @@ class ARandomSpawner : public AActor { if (di->Name != NAME_None) { - if (di->amount < 0) di->amount = 1; // default value is -1, we need a positive value. - n += di->amount; // this is how we can weight the list. + if (di->Amount < 0) di->Amount = 1; // default value is -1, we need a positive value. + n += di->Amount; // this is how we can weight the list. di = di->Next; } } @@ -54,7 +54,7 @@ class ARandomSpawner : public AActor { if (di->Name != NAME_None) { - n -= di->amount; + n -= di->Amount; if ((di->Next != NULL) && (n > -1)) di = di->Next; else n = -1; } } @@ -64,7 +64,7 @@ class ARandomSpawner : public AActor Spawn("Unknown", x, y, z, NO_REPLACE); // Show that there's a problem. Destroy(); return; } - else if (pr_randomspawn() <= di->probability) // prob 255 = always spawn, prob 0 = never spawn. + else if (pr_randomspawn() <= di->Probability) // prob 255 = always spawn, prob 0 = almost never spawn. { // Handle replacement here so as to get the proper speed and flags for missiles PClassActor *cls; diff --git a/src/g_shared/a_weaponpiece.h b/src/g_shared/a_weaponpiece.h index 3d609d8c5..bdc0c80f9 100644 --- a/src/g_shared/a_weaponpiece.h +++ b/src/g_shared/a_weaponpiece.h @@ -13,7 +13,7 @@ public: virtual void PlayPickupSound (AActor *toucher); int PieceValue; - PClassActor *WeaponClass; + PClassWeapon *WeaponClass; TObjPtr<AWeapon> FullWeapon; }; diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index f1f488557..97b438853 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -30,11 +30,29 @@ FString WeaponSection; TArray<FString> KeyConfWeapons; FWeaponSlots *PlayingKeyConf; -TArray<PClassActor *> Weapons_ntoh; -TMap<PClassActor *, int> Weapons_hton; +TArray<PClassWeapon *> Weapons_ntoh; +TMap<PClassWeapon *, int> Weapons_hton; static int STACK_ARGS ntoh_cmp(const void *a, const void *b); +IMPLEMENT_CLASS(PClassWeapon) + +PClassWeapon::PClassWeapon() +{ + SlotNumber = -1; + SlotPriority = FIXED_MAX; +} + +void PClassWeapon::Derive(PClass *newclass) +{ + assert(newclass->IsKindOf(RUNTIME_CLASS(PClassWeapon))); + Super::Derive(newclass); + PClassWeapon *newc = static_cast<PClassWeapon *>(newclass); + + newc->SlotNumber = SlotNumber; + newc->SlotPriority = SlotPriority; +} + //=========================================================================== // // AWeapon :: Serialize @@ -357,7 +375,7 @@ bool AWeapon::AddExistingAmmo (AAmmo *ammo, int amount) // //=========================================================================== -AWeapon *AWeapon::AddWeapon (PClassActor *weapontype) +AWeapon *AWeapon::AddWeapon (PClassWeapon *weapontype) { AWeapon *weap; @@ -620,13 +638,13 @@ IMPLEMENT_CLASS(AWeaponGiver) bool AWeaponGiver::TryPickup(AActor *&toucher) { - FDropItem *di = GetDropItems(); + DDropItem *di = GetDropItems(); AWeapon *weap; if (di != NULL) { - PClassActor *ti = PClass::FindActor(di->Name); - if (ti != NULL && ti->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + PClassWeapon *ti = dyn_cast<PClassWeapon>(PClass::FindClass(di->Name)); + if (ti != NULL) { if (master == NULL) { @@ -662,10 +680,10 @@ bool AWeaponGiver::TryPickup(AActor *&toucher) bool FWeaponSlot::AddWeapon(const char *type) { - return AddWeapon (PClass::FindActor (type)); + return AddWeapon(static_cast<PClassWeapon *>(PClass::FindClass(type))); } -bool FWeaponSlot::AddWeapon(PClassActor *type) +bool FWeaponSlot::AddWeapon(PClassWeapon *type) { unsigned int i; @@ -726,7 +744,7 @@ void FWeaponSlot :: AddWeaponList(const char *list, bool clear) // //=========================================================================== -int FWeaponSlot::LocateWeapon(PClassActor *type) +int FWeaponSlot::LocateWeapon(PClassWeapon *type) { unsigned int i; @@ -842,7 +860,7 @@ void FWeaponSlot::Sort() for (i = 1; i < (int)Weapons.Size(); ++i) { fixed_t pos = Weapons[i].Position; - PClassActor *type = Weapons[i].Type; + PClassWeapon *type = Weapons[i].Type; for (j = i - 1; j >= 0 && Weapons[j].Position > pos; --j) { Weapons[j + 1] = Weapons[j]; @@ -891,7 +909,7 @@ void FWeaponSlots::Clear() // //=========================================================================== -ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, PClassActor *type) +ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, PClassWeapon *type) { int currSlot, index; @@ -916,7 +934,7 @@ ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, PClassActor *type) // //=========================================================================== -bool FWeaponSlots::LocateWeapon (PClassActor *type, int *const slot, int *const index) +bool FWeaponSlots::LocateWeapon (PClassWeapon *type, int *const slot, int *const index) { int i, j; @@ -1014,7 +1032,7 @@ AWeapon *FWeaponSlots::PickNextWeapon(player_t *player) slot = 0; } } - PClassActor *type = Slots[slot].GetWeapon(index); + PClassWeapon *type = Slots[slot].GetWeapon(index); AWeapon *weap = static_cast<AWeapon *>(player->mo->FindInventory(type)); if (weap != NULL && weap->CheckAmmo(AWeapon::EitherFire, false)) { @@ -1069,7 +1087,7 @@ AWeapon *FWeaponSlots::PickPrevWeapon (player_t *player) } index = Slots[slot].Size() - 1; } - PClassActor *type = Slots[slot].GetWeapon(index); + PClassWeapon *type = Slots[slot].GetWeapon(index); AWeapon *weap = static_cast<AWeapon *>(player->mo->FindInventory(type)); if (weap != NULL && weap->CheckAmmo(AWeapon::EitherFire, false)) { @@ -1109,17 +1127,16 @@ void FWeaponSlots::AddExtraWeapons() { continue; } - PClassActor *acls = static_cast<PClassActor *>(cls); + PClassWeapon *acls = static_cast<PClassWeapon *>(cls); if ((acls->GameFilter == GAME_Any || (acls->GameFilter & gameinfo.gametype)) && acls->Replacement == NULL && // Replaced weapons don't get slotted. !LocateWeapon(acls, NULL, NULL) // Don't duplicate it if it's already present. ) { - int slot = acls->Meta.GetMetaInt(AWMETA_SlotNumber, -1); + int slot = acls->SlotNumber; if ((unsigned)slot < NUM_WEAPON_SLOTS) { - fixed_t position = acls->Meta.GetMetaFixed(AWMETA_SlotPriority, INT_MAX); - FWeaponSlot::WeaponInfo info = { acls, position }; + FWeaponSlot::WeaponInfo info = { acls, acls->SlotPriority }; Slots[slot].Weapons.Push(info); } } @@ -1156,7 +1173,7 @@ void FWeaponSlots::SetFromGameInfo() { for (unsigned j = 0; j < gameinfo.DefaultWeaponSlots[i].Size(); i++) { - PClassActor *cls = PClass::FindActor(gameinfo.DefaultWeaponSlots[i][j]); + PClassWeapon *cls = dyn_cast<PClassWeapon>(PClass::FindClass(gameinfo.DefaultWeaponSlots[i][j])); if (cls == NULL) { Printf("Unknown weapon class '%s' found in default weapon slot assignments\n", @@ -1181,7 +1198,7 @@ void FWeaponSlots::SetFromGameInfo() // //=========================================================================== -void FWeaponSlots::StandardSetup(PClassActor *type) +void FWeaponSlots::StandardSetup(PClassPlayerPawn *type) { SetFromPlayer(type); AddExtraWeapons(); @@ -1266,15 +1283,14 @@ void FWeaponSlots::SendDifferences(const FWeaponSlots &other) // //=========================================================================== -void FWeaponSlots::SetFromPlayer(PClassActor *type) +void FWeaponSlots::SetFromPlayer(PClassPlayerPawn *type) { Clear(); for (int i = 0; i < NUM_WEAPON_SLOTS; ++i) { - const char *str = type->Meta.GetMetaString(APMETA_Slot0 + i); - if (str != NULL) + if (!type->Slot[i].IsEmpty()) { - Slots[i].AddWeaponList(str, false); + Slots[i].AddWeaponList(type->Slot[i], false); } } } @@ -1385,7 +1401,7 @@ CCMD (setslot) Net_WriteByte(argv.argc()-2); for (int i = 2; i < argv.argc(); i++) { - Net_WriteWeapon(PClass::FindActor(argv[i])); + Net_WriteWeapon(dyn_cast<PClassWeapon>(PClass::FindClass(argv[i]))); } } } @@ -1396,7 +1412,7 @@ CCMD (setslot) // //=========================================================================== -void FWeaponSlots::AddSlot(int slot, PClassActor *type, bool feedback) +void FWeaponSlots::AddSlot(int slot, PClassWeapon *type, bool feedback) { if (type != NULL && !Slots[slot].AddWeapon(type) && feedback) { @@ -1414,19 +1430,26 @@ CCMD (addslot) return; } + PClassWeapon *type= dyn_cast<PClassWeapon>(PClass::FindClass(argv[2])); + if (type == NULL) + { + Printf("%s is not a weapon\n", argv[2]); + return; + } + if (ParsingKeyConf) { KeyConfWeapons.Push(argv.args()); } else if (PlayingKeyConf != NULL) { - PlayingKeyConf->AddSlot(int(slot), PClass::FindActor(argv[2]), false); + PlayingKeyConf->AddSlot(int(slot), type, false); } else { Net_WriteByte(DEM_ADDSLOT); Net_WriteByte(slot); - Net_WriteWeapon(PClass::FindActor(argv[2])); + Net_WriteWeapon(type); } } @@ -1449,7 +1472,7 @@ CCMD (weaponsection) // CCMD addslotdefault // //=========================================================================== -void FWeaponSlots::AddSlotDefault(int slot, PClassActor *type, bool feedback) +void FWeaponSlots::AddSlotDefault(int slot, PClassWeapon *type, bool feedback) { if (type != NULL && type->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { @@ -1474,7 +1497,7 @@ void FWeaponSlots::AddSlotDefault(int slot, PClassActor *type, bool feedback) CCMD (addslotdefault) { - PClassActor *type; + PClassWeapon *type; unsigned int slot; if (argv.argc() != 3 || (slot = atoi (argv[1])) >= NUM_WEAPON_SLOTS) @@ -1483,8 +1506,8 @@ CCMD (addslotdefault) return; } - type = PClass::FindActor(argv[2]); - if (type == NULL || !type->IsDescendantOf (RUNTIME_CLASS(AWeapon))) + type = dyn_cast<PClassWeapon>(PClass::FindClass(argv[2])); + if (type == NULL) { Printf ("%s is not a weapon\n", argv[2]); return; @@ -1496,13 +1519,13 @@ CCMD (addslotdefault) } else if (PlayingKeyConf != NULL) { - PlayingKeyConf->AddSlotDefault(int(slot), PClass::FindActor(argv[2]), false); + PlayingKeyConf->AddSlotDefault(int(slot), type, false); } else { Net_WriteByte(DEM_ADDSLOTDEFAULT); Net_WriteByte(slot); - Net_WriteWeapon(PClass::FindActor(argv[2])); + Net_WriteWeapon(type); } } @@ -1539,7 +1562,7 @@ void P_PlaybackKeyConfWeapons(FWeaponSlots *slots) void P_SetupWeapons_ntohton() { unsigned int i; - PClassActor *cls; + PClassWeapon *cls; Weapons_ntoh.Clear(); Weapons_hton.Clear(); @@ -1552,7 +1575,7 @@ void P_SetupWeapons_ntohton() if (cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { - Weapons_ntoh.Push(static_cast<PClassActor *>(cls)); + Weapons_ntoh.Push(static_cast<PClassWeapon *>(cls)); } } qsort(&Weapons_ntoh[1], Weapons_ntoh.Size() - 1, sizeof(Weapons_ntoh[0]), ntoh_cmp); @@ -1578,8 +1601,8 @@ void P_SetupWeapons_ntohton() static int STACK_ARGS ntoh_cmp(const void *a, const void *b) { - PClassActor *c1 = *(PClassActor **)a; - PClassActor *c2 = *(PClassActor **)b; + PClassWeapon *c1 = *(PClassWeapon **)a; + PClassWeapon *c2 = *(PClassWeapon **)b; int g1 = c1->GameFilter == GAME_Any ? 1 : (c1->GameFilter & gameinfo.gametype) ? 0 : 2; int g2 = c2->GameFilter == GAME_Any ? 1 : (c2->GameFilter & gameinfo.gametype) ? 0 : 2; if (g1 != g2) @@ -1619,7 +1642,7 @@ void P_WriteDemoWeaponsChunk(BYTE **demo) void P_ReadDemoWeaponsChunk(BYTE **demo) { int count, i; - PClassActor *type; + PClassWeapon *type; const char *s; count = ReadWord(demo); @@ -1632,7 +1655,7 @@ void P_ReadDemoWeaponsChunk(BYTE **demo) for (i = 1; i < count; ++i) { s = ReadStringConst(demo); - type = PClass::FindActor(s); + type = dyn_cast<PClassWeapon>(PClass::FindClass(s)); // If a demo was recorded with a weapon that is no longer present, // should we report it? Weapons_ntoh[i] = type; @@ -1649,7 +1672,7 @@ void P_ReadDemoWeaponsChunk(BYTE **demo) // //=========================================================================== -void Net_WriteWeapon(PClassActor *type) +void Net_WriteWeapon(PClassWeapon *type) { int index, *index_p; @@ -1681,7 +1704,7 @@ void Net_WriteWeapon(PClassActor *type) // //=========================================================================== -PClassActor *Net_ReadWeapon(BYTE **stream) +PClassWeapon *Net_ReadWeapon(BYTE **stream) { int index; diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index cbde68ff9..08086e62c 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -2176,7 +2176,7 @@ class CommandPlayerClass : public SBarInfoCommandFlowControl bool foundClass = false; for(unsigned int c = 0;c < PlayerClasses.Size();c++) { - if(stricmp(sc.String, PlayerClasses[c].Type->Meta.GetMetaString(APMETA_DisplayName)) == 0) + if(stricmp(sc.String, PlayerClasses[c].Type->DisplayName) == 0) { foundClass = true; classes.Push(PlayerClasses[c].Type->ClassIndex); diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index d13fe3fe1..385971d59 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -104,16 +104,14 @@ static int statspace; void AM_GetPosition(fixed_t & x, fixed_t & y); -FTextureID GetHUDIcon(const PClass *cls) +FTextureID GetHUDIcon(PClassInventory *cls) { - FTextureID tex; - tex.texnum = cls->Meta.GetMetaInt(HUMETA_AltIcon, 0); - return tex; + return cls->AltHUDIcon; } -void SetHUDIcon(PClass *cls, FTextureID tex) +void SetHUDIcon(PClassInventory *cls, FTextureID tex) { - cls->Meta.SetMetaInt(HUMETA_AltIcon, tex.GetIndex()); + cls->AltHUDIcon = tex; } //--------------------------------------------------------------------------- @@ -450,14 +448,14 @@ static int DrawKeys(player_t * CPlayer, int x, int y) // Drawing Ammo // //--------------------------------------------------------------------------- -static TArray<PClassActor *> orderedammos; +static TArray<PClassAmmo *> orderedammos; static void AddAmmoToList(AWeapon * weapdef) { for(int i=0; i<2;i++) { - PClassActor * ti = i==0? weapdef->AmmoType1 : weapdef->AmmoType2; + PClassAmmo * ti = i==0? weapdef->AmmoType1 : weapdef->AmmoType2; if (ti) { AAmmo * ammodef=(AAmmo*)GetDefaultByType(ti); @@ -516,7 +514,7 @@ static int DrawAmmo(player_t *CPlayer, int x, int y) for(i=orderedammos.Size()-1;i>=0;i--) { - PClassActor * type = orderedammos[i]; + PClassAmmo * type = orderedammos[i]; AAmmo * ammoitem = (AAmmo*)CPlayer->mo->FindInventory(type); AAmmo * inv = ammoitem? ammoitem : (AAmmo*)GetDefaultByType(orderedammos[i]); @@ -605,16 +603,16 @@ static void DrawOneWeapon(player_t * CPlayer, int x, int & y, AWeapon * weapon) } -static void DrawWeapons(player_t * CPlayer, int x, int y) +static void DrawWeapons(player_t *CPlayer, int x, int y) { int k,j; - AInventory * inv; + AInventory *inv; // First draw all weapons in the inventory that are not assigned to a weapon slot - for(inv=CPlayer->mo->Inventory;inv;inv=inv->Inventory) + for(inv = CPlayer->mo->Inventory; inv; inv = inv->Inventory) { if (inv->IsKindOf(RUNTIME_CLASS(AWeapon)) && - !CPlayer->weapons.LocateWeapon(RUNTIME_TYPE(inv), NULL, NULL)) + !CPlayer->weapons.LocateWeapon(static_cast<AWeapon*>(inv)->GetClass(), NULL, NULL)) { DrawOneWeapon(CPlayer, x, y, static_cast<AWeapon*>(inv)); } @@ -931,7 +929,7 @@ void HUD_InitHud() } else { - const PClass * ti = PClass::FindClass(sc.String); + PClass *ti = PClass::FindClass(sc.String); if (!ti) { Printf("Unknown item class '%s' in ALTHUDCF\n", sc.String); @@ -950,9 +948,8 @@ void HUD_InitHud() } else tex.SetInvalid(); - if (ti) SetHUDIcon(const_cast<PClass*>(ti), tex); + if (ti) SetHUDIcon(static_cast<PClassInventory*>(ti), tex); } } } } - diff --git a/src/g_strife/a_crusader.cpp b/src/g_strife/a_crusader.cpp index 1b32c8051..5d43b030d 100644 --- a/src/g_strife/a_crusader.cpp +++ b/src/g_strife/a_crusader.cpp @@ -29,18 +29,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_CrusaderChoose) { A_FaceTarget (self); self->angle -= ANGLE_180/16; - P_SpawnMissileZAimed (self, self->z + 40*FRACUNIT, self->target, PClass::FindClass("FastFlameMissile")); + P_SpawnMissileZAimed (self, self->z + 40*FRACUNIT, self->target, PClass::FindActor("FastFlameMissile")); } else { if (P_CheckMissileRange (self)) { A_FaceTarget (self); - P_SpawnMissileZAimed (self, self->z + 56*FRACUNIT, self->target, PClass::FindClass("CrusaderMissile")); + P_SpawnMissileZAimed (self, self->z + 56*FRACUNIT, self->target, PClass::FindActor("CrusaderMissile")); self->angle -= ANGLE_45/32; - P_SpawnMissileZAimed (self, self->z + 40*FRACUNIT, self->target, PClass::FindClass("CrusaderMissile")); + P_SpawnMissileZAimed (self, self->z + 40*FRACUNIT, self->target, PClass::FindActor("CrusaderMissile")); self->angle += ANGLE_45/16; - P_SpawnMissileZAimed (self, self->z + 40*FRACUNIT, self->target, PClass::FindClass("CrusaderMissile")); + P_SpawnMissileZAimed (self, self->z + 40*FRACUNIT, self->target, PClass::FindActor("CrusaderMissile")); self->angle -= ANGLE_45/16; self->reactiontime += 15; } @@ -54,7 +54,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CrusaderSweepLeft) PARAM_ACTION_PROLOGUE; self->angle += ANGLE_90/16; - AActor *misl = P_SpawnMissileZAimed (self, self->z + 48*FRACUNIT, self->target, PClass::FindClass("FastFlameMissile")); + AActor *misl = P_SpawnMissileZAimed (self, self->z + 48*FRACUNIT, self->target, PClass::FindActor("FastFlameMissile")); if (misl != NULL) { misl->velz += FRACUNIT; @@ -67,7 +67,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CrusaderSweepRight) PARAM_ACTION_PROLOGUE; self->angle -= ANGLE_90/16; - AActor *misl = P_SpawnMissileZAimed (self, self->z + 48*FRACUNIT, self->target, PClass::FindClass("FastFlameMissile")); + AActor *misl = P_SpawnMissileZAimed (self, self->z + 48*FRACUNIT, self->target, PClass::FindActor("FastFlameMissile")); if (misl != NULL) { misl->velz += FRACUNIT; diff --git a/src/g_strife/a_inquisitor.cpp b/src/g_strife/a_inquisitor.cpp index 3835a314f..0894ffdf0 100644 --- a/src/g_strife/a_inquisitor.cpp +++ b/src/g_strife/a_inquisitor.cpp @@ -63,13 +63,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_InquisitorAttack) self->z += 32*FRACBITS; self->angle -= ANGLE_45/32; - proj = P_SpawnMissileZAimed (self, self->z, self->target, PClass::FindClass("InquisitorShot")); + proj = P_SpawnMissileZAimed (self, self->z, self->target, PClass::FindActor("InquisitorShot")); if (proj != NULL) { proj->velz += 9*FRACUNIT; } self->angle += ANGLE_45/16; - proj = P_SpawnMissileZAimed (self, self->z, self->target, PClass::FindClass("InquisitorShot")); + proj = P_SpawnMissileZAimed (self, self->z, self->target, PClass::FindActor("InquisitorShot")); if (proj != NULL) { proj->velz += 16*FRACUNIT; diff --git a/src/g_strife/a_sentinel.cpp b/src/g_strife/a_sentinel.cpp index 993cd1283..4e9303332 100644 --- a/src/g_strife/a_sentinel.cpp +++ b/src/g_strife/a_sentinel.cpp @@ -53,7 +53,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SentinelAttack) return 0; } - missile = P_SpawnMissileZAimed (self, self->z + 32*FRACUNIT, self->target, PClass::FindClass("SentinelFX2")); + missile = P_SpawnMissileZAimed (self, self->z + 32*FRACUNIT, self->target, PClass::FindActor("SentinelFX2")); if (missile != NULL && (missile->velx | missile->vely) != 0) { diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp index 3cd8a15b2..4e3db52ae 100644 --- a/src/g_strife/a_strifeweapons.cpp +++ b/src/g_strife/a_strifeweapons.cpp @@ -341,7 +341,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMiniMissile) savedangle = self->angle; self->angle += pr_minimissile.Random2() << (19 - player->accuracy * 5 / 100); player->mo->PlayAttacking2 (); - P_SpawnPlayerMissile (self, PClass::FindClass("MiniMissile")); + P_SpawnPlayerMissile (self, PClass::FindActor("MiniMissile")); self->angle = savedangle; return 0; } @@ -359,7 +359,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RocketInFlight) AActor *trail; S_Sound (self, CHAN_VOICE, "misc/missileinflight", 1, ATTN_NORM); - P_SpawnPuff (self, PClass::FindClass("MiniMissilePuff"), self->x, self->y, self->z, self->angle - ANGLE_180, 2, PF_HITTHING); + P_SpawnPuff (self, PClass::FindActor("MiniMissilePuff"), self->x, self->y, self->z, self->angle - ANGLE_180, 2, PF_HITTHING); trail = Spawn("RocketTrail", self->x - self->velx, self->y - self->vely, self->z, ALLOW_REPLACE); if (trail != NULL) { @@ -409,7 +409,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireFlamer) } self->angle += pr_flamethrower.Random2() << 18; - self = P_SpawnPlayerMissile (self, PClass::FindClass("FlameMissile")); + self = P_SpawnPlayerMissile (self, PClass::FindActor("FlameMissile")); if (self != NULL) { self->velz += 5*FRACUNIT; @@ -508,7 +508,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMauler2) } self->player->mo->PlayAttacking2 (); } - P_SpawnPlayerMissile (self, PClass::FindClass("MaulerTorpedo")); + P_SpawnPlayerMissile (self, PClass::FindActor("MaulerTorpedo")); P_DamageMobj (self, self, NULL, 20, self->DamageType); P_ThrustMobj (self, self->angle + ANGLE_180, 0x7D000); return 0; @@ -1012,7 +1012,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil2) P_DamageMobj (self, self, NULL, 2*4, 0, DMG_NO_ARMOR); S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); - P_SpawnPlayerMissile (self, PClass::FindClass("SpectralLightningH1")); + P_SpawnPlayerMissile (self, PClass::FindActor("SpectralLightningH1")); return 0; } @@ -1073,7 +1073,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil4) P_BulletSlope (self, &linetarget); if (linetarget != NULL) { - spot = P_SpawnPlayerMissile (self, 0,0,0, PClass::FindClass("SpectralLightningBigV1"), self->angle, &linetarget); + spot = P_SpawnPlayerMissile (self, 0,0,0, PClass::FindActor("SpectralLightningBigV1"), self->angle, &linetarget); if (spot != NULL) { spot->tracer = linetarget; @@ -1081,7 +1081,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil4) } else { - spot = P_SpawnPlayerMissile (self, PClass::FindClass("SpectralLightningBigV1")); + spot = P_SpawnPlayerMissile (self, PClass::FindActor("SpectralLightningBigV1")); if (spot != NULL) { spot->velx += FixedMul (spot->Speed, finecosine[self->angle >> ANGLETOFINESHIFT]); @@ -1109,7 +1109,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil5) P_DamageMobj (self, self, NULL, 5*4, 0, DMG_NO_ARMOR); S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); - P_SpawnPlayerMissile (self, PClass::FindClass("SpectralLightningBigBall1")); + P_SpawnPlayerMissile (self, PClass::FindActor("SpectralLightningBigBall1")); return 0; } diff --git a/src/info.cpp b/src/info.cpp index 4f666b767..652e1c1aa 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -107,7 +107,9 @@ int GetSpriteIndex(const char * spritename) return (lastindex = (int)sprites.Push (temp)); } -IMPLEMENT_CLASS(PClassActor) +IMPLEMENT_POINTY_CLASS(PClassActor) + DECLARE_POINTER(DropItems) +END_POINTERS //========================================================================== // @@ -173,6 +175,28 @@ PClassActor::PClassActor() StateList = NULL; DamageFactors = NULL; PainChances = NULL; + + Obituary = Obituary; + HitObituary = HitObituary; + DeathHeight = -1; + BurnHeight = -1; + GibHealth = INT_MIN; + WoundHealth = 6; + PoisonDamage = 0; + FastSpeed = FIXED_MIN; + RDFactor = FRACUNIT; + CameraHeight = FIXED_MIN; + BloodType = NAME_Blood; + BloodType2 = NAME_BloodSplatter; + BloodType3 = NAME_AxeBlood; + + DropItems = NULL; + + DontHurtShooter = false; + ExplosionDamage = 128; + ExplosionRadius = -1; + MissileHeight = 32*FRACUNIT; + MeleeDamage = 0; } //========================================================================== @@ -202,6 +226,45 @@ PClassActor::~PClassActor() } } +//========================================================================== +// +// PClassActor :: Derive +// +//========================================================================== + +void PClassActor::Derive(PClass *newclass) +{ + assert(newclass->IsKindOf(RUNTIME_CLASS(PClassActor))); + Super::Derive(newclass); + PClassActor *newa = static_cast<PClassActor *>(newclass); + + newa->Obituary = Obituary; + newa->HitObituary = HitObituary; + newa->DeathHeight = DeathHeight; + newa->BurnHeight = BurnHeight; + newa->BloodColor = BloodColor; + newa->GibHealth = GibHealth; + newa->WoundHealth = WoundHealth; + newa->PoisonDamage = PoisonDamage; + newa->FastSpeed = FastSpeed; + newa->RDFactor = RDFactor; + newa->CameraHeight = CameraHeight; + newa->HowlSound = HowlSound; + newa->BloodType = BloodType; + newa->BloodType2 = BloodType2; + newa->BloodType3 = BloodType3; + + newa->DropItems = DropItems; + + newa->DontHurtShooter = DontHurtShooter; + newa->ExplosionRadius = ExplosionRadius; + newa->ExplosionDamage = ExplosionDamage; + newa->MeleeDamage = MeleeDamage; + newa->MeleeSound = MeleeSound; + newa->MissileName = MissileName; + newa->MissileHeight = MissileHeight; +} + //========================================================================== // // PClassActor :: PropagateMark diff --git a/src/info.h b/src/info.h index ebc2f1250..bf7a38fbc 100644 --- a/src/info.h +++ b/src/info.h @@ -44,6 +44,7 @@ #include "dobject.h" #include "doomdef.h" #include "vm.h" +#include "s_sound.h" const BYTE SF_FULLBRIGHT = 0x40; @@ -124,10 +125,14 @@ FArchive &operator<< (FArchive &arc, FState *&state); typedef TMap<FName, fixed_t> DmgFactors; typedef TMap<FName, BYTE> PainChanceList; +class DDropItem; class PClassActor : public PClass { DECLARE_CLASS(PClassActor, PClass); + HAS_OBJECT_POINTERS; +protected: + virtual void Derive(PClass *newclass); public: static void StaticInit (); static void StaticSetActorNums (); @@ -163,6 +168,32 @@ public: FStateLabels *StateList; DmgFactors *DamageFactors; PainChanceList *PainChances; + FString Obituary; // Player was killed by this actor + FString HitObituary; // Player was killed by this actor in melee + fixed_t DeathHeight; // Height on normal death + fixed_t BurnHeight; // Height on burning death + PalEntry BloodColor; // Colorized blood + int GibHealth; // Negative health below which this monster dies an extreme death + int WoundHealth; // Health needed to enter wound state + int PoisonDamage; // Amount of poison damage + fixed_t FastSpeed; // Speed in fast mode + fixed_t RDFactor; // Radius damage factor + fixed_t CameraHeight; // Height of camera when used as such + FSoundID HowlSound; // Sound being played when electrocuted or poisoned + FName BloodType; // Blood replacement type + FName BloodType2; // Bloopsplatter replacement type + FName BloodType3; // AxeBlood replacement type + + DDropItem *DropItems; + + // Old Decorate compatibility stuff + bool DontHurtShooter; + int ExplosionRadius; + int ExplosionDamage; + int MeleeDamage; + FSoundID MeleeSound; + FName MissileName; + fixed_t MissileHeight; }; inline PClassActor *PClass::FindActor(FName name) diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index abf2983ae..ad948264e 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -144,7 +144,7 @@ void cht_DoCheat (player_t *player, int cheat) break; case CHT_MORPH: - msg = cht_Morph (player, PClass::FindClass (gameinfo.gametype == GAME_Heretic ? NAME_ChickenPlayer : NAME_PigPlayer), true); + msg = cht_Morph (player, static_cast<PClassPlayerPawn *>(PClass::FindClass (gameinfo.gametype == GAME_Heretic ? NAME_ChickenPlayer : NAME_PigPlayer)), true); break; case CHT_NOTARGET: @@ -521,13 +521,13 @@ void cht_DoCheat (player_t *player, int cheat) Printf ("%s is a cheater: %s\n", player->userinfo.netname, msg); } -const char *cht_Morph (player_t *player, const PClass *morphclass, bool quickundo) +const char *cht_Morph (player_t *player, PClassPlayerPawn *morphclass, bool quickundo) { if (player->mo == NULL) { return ""; } - PClass *oldclass = player->mo->GetClass(); + PClassPlayerPawn *oldclass = player->mo->GetClass(); // Set the standard morph style for the current game int style = MORPH_UNDOBYTOMEOFPOWER; @@ -750,7 +750,7 @@ void cht_Give (player_t *player, const char *name, int amount) // is in a weapon slot. if (static_cast<PClassActor *>(type)->GameFilter == GAME_Any || (static_cast<PClassActor *>(type)->GameFilter & gameinfo.gametype) || - player->weapons.LocateWeapon(static_cast<PClassActor *>(type), NULL, NULL)) + player->weapons.LocateWeapon(static_cast<PClassWeapon *>(type), NULL, NULL)) { AWeapon *def = (AWeapon*)GetDefaultByType (type); if (!(def->WeaponFlags & WIF_CHEATNOTWEAPON)) diff --git a/src/m_cheat.h b/src/m_cheat.h index e56c69198..9480b3372 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -29,11 +29,12 @@ // [RH] Functions that actually perform the cheating class player_t; -class PClass; +class PClassPlayerPawn; + void cht_DoCheat (player_t *player, int cheat); void cht_Give (player_t *player, const char *item, int amount=1); void cht_Take (player_t *player, const char *item, int amount=1); void cht_Suicide (player_t *player); -const char *cht_Morph (player_t *player, const PClass *morphclass, bool quickundo); +const char *cht_Morph (player_t *player, PClassPlayerPawn *morphclass, bool quickundo); #endif diff --git a/src/m_menu.cpp b/src/m_menu.cpp index 88eac1edf..2045e064d 100644 --- a/src/m_menu.cpp +++ b/src/m_menu.cpp @@ -1883,7 +1883,7 @@ static void SCClass (int option) if (option == 3) playerclass = "Random"; else - playerclass = PlayerClasses[option].Type->Meta.GetMetaString (APMETA_DisplayName); + playerclass = PlayerClasses[option].Type->DisplayName; if (EpiDef.numitems > 1) { @@ -2299,7 +2299,7 @@ static void M_PlayerSetupDrawer () x = SmallFont->StringWidth ("Class") + 8 + PSetupDef.x; screen->DrawText (SmallFont, label, PSetupDef.x, PSetupDef.y + LINEHEIGHT*5+yo, "Class", DTA_Clean, true, TAG_DONE); screen->DrawText (SmallFont, value, x, PSetupDef.y + LINEHEIGHT*5+yo, - pclass == -1 ? "Random" : PlayerClasses[pclass].Type->Meta.GetMetaString (APMETA_DisplayName), + pclass == -1 ? "Random" : PlayerClasses[pclass].Type->DisplayName, DTA_Clean, true, TAG_DONE); // Draw skin setting @@ -2567,8 +2567,7 @@ static void M_ChangeClass (int choice) else type = (type < (int)PlayerClasses.Size () - 1) ? type + 1 : -1; - cvar_set ("playerclass", type < 0 ? "Random" : - PlayerClasses[type].Type->Meta.GetMetaString (APMETA_DisplayName)); + cvar_set ("playerclass", type < 0 ? "Random" : PlayerClasses[type].Type->DisplayName); } static void M_ChangeSkin (int choice) @@ -3964,8 +3963,7 @@ void M_Init (void) { if (!(PlayerClasses[i].Flags & PCF_NOMENU)) { - ClassMenuItems[n].name = - PlayerClasses[i].Type->Meta.GetMetaString (APMETA_DisplayName); + ClassMenuItems[n].name = PlayerClasses[i].Type->DisplayName; n++; } } @@ -3979,8 +3977,7 @@ void M_Init (void) { if (n == 0) { - ClassMenuItems[0].name = - PlayerClasses[0].Type->Meta.GetMetaString (APMETA_DisplayName); + ClassMenuItems[0].name = PlayerClasses[0].Type->DisplayName; } ClassMenuDef.numitems = 1; } diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 7afc750f7..576709a9d 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -3109,7 +3109,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) } else { - return actor->GetClass()->Meta.GetMetaFixed(AMETA_CameraHeight, actor->height/2); + return actor->GetCameraHeight(); } } else return 0; @@ -6358,7 +6358,7 @@ int DLevelScript::RunScript () { int tag = STACK(7); FName playerclass_name = FBehavior::StaticLookupString(STACK(6)); - const PClass *playerclass = PClass::FindClass (playerclass_name); + PClassPlayerPawn *playerclass = dyn_cast<PClassPlayerPawn>(PClass::FindClass (playerclass_name)); FName monsterclass_name = FBehavior::StaticLookupString(STACK(5)); const PClass *monsterclass = PClass::FindClass (monsterclass_name); int duration = STACK(4); diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index cd94bf76d..c08e9ff7f 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -2877,8 +2877,13 @@ void ModifyDropAmount(AInventory *inv, int dropamount) else if (inv->IsKindOf (RUNTIME_CLASS(AAmmo))) { // Half ammo when dropped by bad guys. - inv->Amount = inv->GetClass()->Meta.GetMetaInt (AIMETA_DropAmount, MAX(1, FixedMul(inv->Amount, dropammofactor))); - inv->ItemFlags|=flagmask; + int amount = static_cast<PClassAmmo *>(inv->GetClass())->DropAmount; + if (amount <= 0) + { + amount = FixedMul(inv->Amount, dropammofactor); + } + inv->Amount = amount; + inv->ItemFlags |= flagmask; } else if (inv->IsKindOf (RUNTIME_CLASS(AWeapon))) { diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 3952251a2..176309f44 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -243,17 +243,13 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker) { message = GStrings("OB_MONTELEFRAG"); } - else if (mod == NAME_Melee) + else if (mod == NAME_Melee && attacker->GetClass()->HitObituary.IsNotEmpty()) { - message = attacker->GetClass()->Meta.GetMetaString (AMETA_HitObituary); - if (message == NULL) - { - message = attacker->GetClass()->Meta.GetMetaString (AMETA_Obituary); - } + message = attacker->GetClass()->HitObituary; } - else + else if (attacker->GetClass()->Obituary.IsNotEmpty()) { - message = attacker->GetClass()->Meta.GetMetaString (AMETA_Obituary); + message = attacker->GetClass()->Obituary; } } } @@ -274,13 +270,13 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker) if (mod == NAME_Telefrag) message = GStrings("OB_MPTELEFRAG"); if (message == NULL) { - if (inflictor != NULL) + if (inflictor != NULL && inflictor->GetClass()->Obituary.IsNotEmpty()) { - message = inflictor->GetClass()->Meta.GetMetaString (AMETA_Obituary); + message = inflictor->GetClass()->Obituary; } - if (message == NULL && attacker->player->ReadyWeapon != NULL) + if (message == NULL && attacker->player->ReadyWeapon != NULL && attacker->player->ReadyWeapon->GetClass()->Obituary.IsNotEmpty()) { - message = attacker->player->ReadyWeapon->GetClass()->Meta.GetMetaString (AMETA_Obituary); + message = attacker->player->ReadyWeapon->GetClass()->Obituary; } if (message == NULL) { @@ -320,12 +316,7 @@ EXTERN_CVAR (Int, fraglimit) static int GibHealth(AActor *actor) { - return -abs( - actor->GetClass()->Meta.GetMetaInt ( - AMETA_GibHealth, - gameinfo.gametype & GAME_DoomChex ? - -actor->SpawnHealth() : - -actor->SpawnHealth()/2)); + return -abs(actor->GetGibHealth()); } void AActor::Die (AActor *source, AActor *inflictor) @@ -399,22 +390,22 @@ void AActor::Die (AActor *source, AActor *inflictor) flags6 |= MF6_KILLED; // [RH] Allow the death height to be overridden using metadata. - fixed_t metaheight = 0; + fixed_t metaheight = -1; if (DamageType == NAME_Fire) { - metaheight = GetClass()->Meta.GetMetaFixed (AMETA_BurnHeight); + metaheight = GetClass()->BurnHeight; } - if (metaheight == 0) + if (metaheight < 0) { - metaheight = GetClass()->Meta.GetMetaFixed (AMETA_DeathHeight); + metaheight = GetClass()->DeathHeight; } - if (metaheight != 0) + if (metaheight < 0) { - height = MAX<fixed_t> (metaheight, 0); + height >>= 2; } else { - height >>= 2; + height = MAX<fixed_t> (metaheight, 0); } // [RH] If the thing has a special, execute and remove it @@ -1271,7 +1262,7 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage woundstate = target->FindState(NAME_Wound, mod); if (woundstate != NULL) { - int woundhealth = RUNTIME_TYPE(target)->Meta.GetMetaInt (AMETA_WoundHealth, 6); + int woundhealth = target->GetClass()->WoundHealth; if (target->health <= woundhealth) { diff --git a/src/p_local.h b/src/p_local.h index 89c8f07ea..822d6f787 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -103,7 +103,7 @@ enum EPuffFlags PF_TEMPORARY = 4 }; -AActor *P_SpawnPuff (AActor *source, const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags = 0); +AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags = 0); void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AActor *originator); void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator); void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator); @@ -114,15 +114,15 @@ void P_ExplodeMissile (AActor *missile, line_t *explodeline, AActor *target); AActor *P_SpawnMissile (AActor* source, AActor* dest, const PClass *type, AActor* owner = NULL); AActor *P_SpawnMissileZ (AActor* source, fixed_t z, AActor* dest, const PClass *type); AActor *P_SpawnMissileXYZ (fixed_t x, fixed_t y, fixed_t z, AActor *source, AActor *dest, const PClass *type, bool checkspawn = true, AActor *owner = NULL); -AActor *P_SpawnMissileAngle (AActor *source, const PClass *type, angle_t angle, fixed_t velz); -AActor *P_SpawnMissileAngleSpeed (AActor *source, const PClass *type, angle_t angle, fixed_t velz, fixed_t speed); -AActor *P_SpawnMissileAngleZ (AActor *source, fixed_t z, const PClass *type, angle_t angle, fixed_t velz); -AActor *P_SpawnMissileAngleZSpeed (AActor *source, fixed_t z, const PClass *type, angle_t angle, fixed_t velz, fixed_t speed, AActor *owner=NULL, bool checkspawn = true); -AActor *P_SpawnMissileZAimed (AActor *source, fixed_t z, AActor *dest, const PClass *type); +AActor *P_SpawnMissileAngle (AActor *source, PClassActor *type, angle_t angle, fixed_t velz); +AActor *P_SpawnMissileAngleSpeed (AActor *source, PClassActor *type, angle_t angle, fixed_t velz, fixed_t speed); +AActor *P_SpawnMissileAngleZ (AActor *source, fixed_t z, PClassActor *type, angle_t angle, fixed_t velz); +AActor *P_SpawnMissileAngleZSpeed (AActor *source, fixed_t z, PClassActor *type, angle_t angle, fixed_t velz, fixed_t speed, AActor *owner=NULL, bool checkspawn = true); +AActor *P_SpawnMissileZAimed (AActor *source, fixed_t z, AActor *dest, PClassActor *type); -AActor *P_SpawnPlayerMissile (AActor* source, const PClass *type); -AActor *P_SpawnPlayerMissile (AActor *source, const PClass *type, angle_t angle); -AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, const PClass *type, angle_t angle, +AActor *P_SpawnPlayerMissile (AActor* source, PClassActor *type); +AActor *P_SpawnPlayerMissile (AActor *source, PClassActor *type, angle_t angle); +AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, PClassActor *type, angle_t angle, AActor **pLineTarget = NULL, AActor **MissileActor = NULL, bool nofreeaim = false); void P_CheckFakeFloorTriggers (AActor *mo, fixed_t oldz, bool oldz_has_viewheight=false); diff --git a/src/p_map.cpp b/src/p_map.cpp index 0642ee440..02eb8aa3f 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -3588,7 +3588,7 @@ void P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *actor, a { if (bleedtrace.HitType == TRACE_HitWall) { - PalEntry bloodcolor = (PalEntry)actor->GetClass()->Meta.GetMetaInt(AMETA_BloodColor); + PalEntry bloodcolor = actor->GetClass()->BloodColor; if (bloodcolor != 0) { bloodcolor.r>>=1; // the full color is too bright for blood decals @@ -4325,7 +4325,7 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b { points = points * splashfactor; } - points *= thing->GetClass()->Meta.GetMetaFixed(AMETA_RDFactor, FRACUNIT)/(float)FRACUNIT; + points *= thing->GetClass()->RDFactor/(float)FRACUNIT; if (points > 0.f && P_CheckSight (thing, bombspot, 1)) { // OK to damage; target is in direct path @@ -4391,7 +4391,7 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b int damage = Scale (bombdamage, bombdistance-dist, bombdistance); damage = (int)((float)damage * splashfactor); - damage = Scale(damage, thing->GetClass()->Meta.GetMetaFixed(AMETA_RDFactor, FRACUNIT), FRACUNIT); + damage = Scale(damage, thing->GetClass()->RDFactor, FRACUNIT); if (damage > 0) { P_DamageMobj (thing, bombspot, bombsource, damage, bombmod); @@ -4598,8 +4598,8 @@ void P_DoCrunch (AActor *thing, FChangePosition *cpos) if ((!(thing->flags&MF_NOBLOOD)) && (!(thing->flags2&(MF2_INVULNERABLE|MF2_DORMANT)))) { - PalEntry bloodcolor = (PalEntry)thing->GetClass()->Meta.GetMetaInt(AMETA_BloodColor); - const PClass *bloodcls = PClass::FindClass((ENamedName)thing->GetClass()->Meta.GetMetaInt(AMETA_BloodType, NAME_Blood)); + PalEntry bloodcolor = thing->GetClass()->BloodColor; + PClassActor *bloodcls = PClass::FindActor(thing->GetClass()->BloodType); P_TraceBleed (cpos->crushchange, thing); if (cl_bloodtype <= 1 && bloodcls != NULL) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index e3b0dbba8..9c0ddbdb3 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1069,7 +1069,7 @@ bool AActor::Grind(bool items) if (isgeneric) // Not a custom crush state, so colorize it appropriately. { S_Sound (this, CHAN_BODY, "misc/fallingsplat", 1, ATTN_IDLE); - PalEntry bloodcolor = PalEntry(GetClass()->Meta.GetMetaInt(AMETA_BloodColor)); + PalEntry bloodcolor = GetClass()->BloodColor; if (bloodcolor!=0) Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a); } return false; @@ -1113,7 +1113,7 @@ bool AActor::Grind(bool items) } S_Sound (this, CHAN_BODY, "misc/fallingsplat", 1, ATTN_IDLE); - PalEntry bloodcolor = (PalEntry)this->GetClass()->Meta.GetMetaInt(AMETA_BloodColor); + PalEntry bloodcolor = GetClass()->BloodColor; if (bloodcolor!=0) gib->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a); } if (flags & MF_ICECORPSE) @@ -2651,7 +2651,7 @@ int AActor::GetMissileDamage (int mask, int add) void AActor::Howl () { - int howl = GetClass()->Meta.GetMetaInt(AMETA_HowlSound); + FSoundID howl = GetClass()->HowlSound; if (!S_IsActorPlayingSomething(this, CHAN_BODY, howl)) { S_Sound (this, CHAN_BODY, howl, 1, ATTN_NORM); @@ -3553,9 +3553,8 @@ AActor *AActor::StaticSpawn (PClassActor *type, fixed_t ix, fixed_t iy, fixed_t actor->frame = st->GetFrame(); actor->renderflags = (actor->renderflags & ~RF_FULLBRIGHT) | st->GetFullbright(); actor->touching_sectorlist = NULL; // NULL head of sector list // phares 3/13/98 - if (G_SkillProperty(SKILLP_FastMonsters)) - actor->Speed = actor->GetClass()->Meta.GetMetaFixed(AMETA_FastSpeed, actor->Speed); - + if (G_SkillProperty(SKILLP_FastMonsters) && actor->GetClass()->FastSpeed >= 0) + actor->Speed = actor->GetClass()->FastSpeed; // set subsector and/or block links actor->LinkToWorld (SpawningMapThing); @@ -4445,7 +4444,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) // P_SpawnPuff // -AActor *P_SpawnPuff (AActor *source, const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags) +AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags) { AActor *puff; @@ -4507,8 +4506,8 @@ AActor *P_SpawnPuff (AActor *source, const PClass *pufftype, fixed_t x, fixed_t void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AActor *originator) { AActor *th; - PalEntry bloodcolor = (PalEntry)originator->GetClass()->Meta.GetMetaInt(AMETA_BloodColor); - const PClass *bloodcls = PClass::FindClass((ENamedName)originator->GetClass()->Meta.GetMetaInt(AMETA_BloodType, NAME_Blood)); + PalEntry bloodcolor = originator->GetClass()->BloodColor; + PClassActor *bloodcls = PClass::FindActor(originator->GetClass()->BloodType); int bloodtype = cl_bloodtype; @@ -4569,15 +4568,15 @@ void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AAc void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator) { - PalEntry bloodcolor = (PalEntry)originator->GetClass()->Meta.GetMetaInt(AMETA_BloodColor); - const PClass *bloodcls = PClass::FindClass((ENamedName)originator->GetClass()->Meta.GetMetaInt(AMETA_BloodType2, NAME_BloodSplatter)); + PalEntry bloodcolor = originator->GetClass()->BloodColor; + PClassActor *bloodcls = PClass::FindActor(originator->GetClass()->BloodType2); int bloodtype = cl_bloodtype; if (bloodcls != NULL && !(GetDefaultByType(bloodcls)->flags4 & MF4_ALLOWPARTICLES)) bloodtype = 0; - if (bloodcls!=NULL && bloodtype <= 1) + if (bloodcls != NULL && bloodtype <= 1) { AActor *mo; @@ -4607,8 +4606,8 @@ void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator) void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator) { - PalEntry bloodcolor = (PalEntry)originator->GetClass()->Meta.GetMetaInt(AMETA_BloodColor); - const PClass *bloodcls = PClass::FindClass((ENamedName)originator->GetClass()->Meta.GetMetaInt(AMETA_BloodType3, NAME_AxeBlood)); + PalEntry bloodcolor = originator->GetClass()->BloodColor; + PClassActor *bloodcls = PClass::FindActor(originator->GetClass()->BloodType3); int bloodtype = cl_bloodtype; @@ -4646,8 +4645,8 @@ void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator) void P_RipperBlood (AActor *mo, AActor *bleeder) { fixed_t x, y, z; - PalEntry bloodcolor = (PalEntry)bleeder->GetClass()->Meta.GetMetaInt(AMETA_BloodColor); - const PClass *bloodcls = PClass::FindClass((ENamedName)bleeder->GetClass()->Meta.GetMetaInt(AMETA_BloodType, NAME_Blood)); + PalEntry bloodcolor = bleeder->GetClass()->BloodColor; + PClassActor *bloodcls = PClass::FindActor(bleeder->GetClass()->BloodType); x = mo->x + (pr_ripperblood.Random2 () << 12); y = mo->y + (pr_ripperblood.Random2 () << 12); @@ -5031,11 +5030,12 @@ void P_PlaySpawnSound(AActor *missile, AActor *spawner) } } -static fixed_t GetDefaultSpeed(const PClass *type) +static fixed_t GetDefaultSpeed(PClassActor *type) { - if (type == NULL) return 0; - else if (G_SkillProperty(SKILLP_FastMonsters)) - return type->Meta.GetMetaFixed(AMETA_FastSpeed, GetDefaultByType(type)->Speed); + if (type == NULL) + return 0; + else if (G_SkillProperty(SKILLP_FastMonsters) && type->FastSpeed >= 0) + return type->FastSpeed; else return GetDefaultByType(type)->Speed; } @@ -5158,7 +5158,7 @@ AActor * P_OldSpawnMissile(AActor * source, AActor * owner, AActor * dest, const // //--------------------------------------------------------------------------- -AActor *P_SpawnMissileAngle (AActor *source, const PClass *type, +AActor *P_SpawnMissileAngle (AActor *source, PClassActor *type, angle_t angle, fixed_t velz) { return P_SpawnMissileAngleZSpeed (source, source->z + 32*FRACUNIT, @@ -5166,13 +5166,13 @@ AActor *P_SpawnMissileAngle (AActor *source, const PClass *type, } AActor *P_SpawnMissileAngleZ (AActor *source, fixed_t z, - const PClass *type, angle_t angle, fixed_t velz) + PClassActor *type, angle_t angle, fixed_t velz) { return P_SpawnMissileAngleZSpeed (source, z, type, angle, velz, GetDefaultSpeed (type)); } -AActor *P_SpawnMissileZAimed (AActor *source, fixed_t z, AActor *dest, const PClass *type) +AActor *P_SpawnMissileZAimed (AActor *source, fixed_t z, AActor *dest, PClassActor *type) { angle_t an; fixed_t dist; @@ -5201,7 +5201,7 @@ AActor *P_SpawnMissileZAimed (AActor *source, fixed_t z, AActor *dest, const PCl // //--------------------------------------------------------------------------- -AActor *P_SpawnMissileAngleSpeed (AActor *source, const PClass *type, +AActor *P_SpawnMissileAngleSpeed (AActor *source, PClassActor *type, angle_t angle, fixed_t velz, fixed_t speed) { return P_SpawnMissileAngleZSpeed (source, source->z + 32*FRACUNIT, @@ -5209,7 +5209,7 @@ AActor *P_SpawnMissileAngleSpeed (AActor *source, const PClass *type, } AActor *P_SpawnMissileAngleZSpeed (AActor *source, fixed_t z, - const PClass *type, angle_t angle, fixed_t velz, fixed_t speed, AActor *owner, bool checkspawn) + PClassActor *type, angle_t angle, fixed_t velz, fixed_t speed, AActor *owner, bool checkspawn) { AActor *mo; @@ -5239,18 +5239,18 @@ AActor *P_SpawnMissileAngleZSpeed (AActor *source, fixed_t z, ================ */ -AActor *P_SpawnPlayerMissile (AActor *source, const PClass *type) +AActor *P_SpawnPlayerMissile (AActor *source, PClassActor *type) { return P_SpawnPlayerMissile (source, 0, 0, 0, type, source->angle); } -AActor *P_SpawnPlayerMissile (AActor *source, const PClass *type, angle_t angle) +AActor *P_SpawnPlayerMissile (AActor *source, PClassActor *type, angle_t angle) { return P_SpawnPlayerMissile (source, 0, 0, 0, type, angle); } AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, - const PClass *type, angle_t angle, AActor **pLineTarget, AActor **pMissileActor, + PClassActor *type, angle_t angle, AActor **pLineTarget, AActor **pMissileActor, bool nofreeaim) { static const int angdiff[3] = { -1<<26, 1<<26, 0 }; @@ -5451,7 +5451,7 @@ int AActor::DoSpecialDamage (AActor *target, int damage) { if (target->player) { - int poisondamage = GetClass()->Meta.GetMetaInt(AMETA_PoisonDamage); + int poisondamage = GetClass()->PoisonDamage; if (poisondamage > 0) { P_PoisonPlayer (target->player, this, this->target, poisondamage); @@ -5512,8 +5512,7 @@ void AActor::Crash() } if (crashstate == NULL) { - int gibhealth = -abs(GetClass()->Meta.GetMetaInt (AMETA_GibHealth, - gameinfo.gametype & GAME_DoomChex ? -SpawnHealth() : -SpawnHealth()/2)); + int gibhealth = GetGibHealth(); if (health < gibhealth) { // Extreme death @@ -5538,7 +5537,7 @@ void AActor::SetIdle() SetState(idle); } -int AActor::SpawnHealth() +int AActor::SpawnHealth() const { if (!(flags3 & MF3_ISMONSTER) || GetDefault()->health == 0) { @@ -5556,15 +5555,32 @@ int AActor::SpawnHealth() } } -FDropItem *AActor::GetDropItems() +int AActor::GetGibHealth() const { - unsigned int index = GetClass()->Meta.GetMetaInt (ACMETA_DropItems) - 1; + int gibhealth = GetClass()->GibHealth; - if (index >= 0 && index < DropItemList.Size()) + if (gibhealth != INT_MIN) { - return DropItemList[index]; + return gibhealth; } - return NULL; + else if (gameinfo.gametype & GAME_DoomChex) + { + return -SpawnHealth(); + } + else + { + return -SpawnHealth()/2; + } +} + +fixed_t AActor::GetCameraHeight() const +{ + return GetClass()->CameraHeight == FIXED_MIN ? height / 2 : GetClass()->CameraHeight; +} + +DDropItem *AActor::GetDropItems() const +{ + return GetClass()->DropItems; } fixed_t AActor::GetGravity() const @@ -5595,30 +5611,9 @@ const char *AActor::GetTag(const char *def) const // DropItem handling // //---------------------------------------------------------------------------- -FDropItemPtrArray DropItemList; - -void FreeDropItemChain(FDropItem *chain) -{ - while (chain != NULL) - { - FDropItem *next = chain->Next; - delete chain; - chain = next; - } -} - -FDropItemPtrArray::~FDropItemPtrArray() -{ - for (unsigned int i = 0; i < Size(); ++i) - { - FreeDropItemChain ((*this)[i]); - } -} - -int StoreDropItemChain(FDropItem *chain) -{ - return DropItemList.Push (chain) + 1; -} +IMPLEMENT_POINTY_CLASS(DDropItem) + DECLARE_POINTER(Next) +END_POINTERS void PrintMiscActorInfo(AActor * query) { diff --git a/src/p_user.cpp b/src/p_user.cpp index 77cd52fb7..e76d706b8 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -104,32 +104,32 @@ void SetupPlayerClasses () if (gameinfo.gametype == GAME_Doom) { - newclass.Type = PClass::FindClass (NAME_DoomPlayer); - PlayerClasses.Push (newclass); + newclass.Type = static_cast<PClassPlayerPawn *>(PClass::FindClass(NAME_DoomPlayer)); + PlayerClasses.Push(newclass); } else if (gameinfo.gametype == GAME_Heretic) { - newclass.Type = PClass::FindClass (NAME_HereticPlayer); - PlayerClasses.Push (newclass); + newclass.Type = static_cast<PClassPlayerPawn *>(PClass::FindClass(NAME_HereticPlayer)); + PlayerClasses.Push(newclass); } else if (gameinfo.gametype == GAME_Hexen) { - newclass.Type = PClass::FindClass (NAME_FighterPlayer); - PlayerClasses.Push (newclass); - newclass.Type = PClass::FindClass (NAME_ClericPlayer); - PlayerClasses.Push (newclass); - newclass.Type = PClass::FindClass (NAME_MagePlayer); - PlayerClasses.Push (newclass); + newclass.Type = static_cast<PClassPlayerPawn *>(PClass::FindClass(NAME_FighterPlayer)); + PlayerClasses.Push(newclass); + newclass.Type = static_cast<PClassPlayerPawn *>(PClass::FindClass(NAME_ClericPlayer)); + PlayerClasses.Push(newclass); + newclass.Type = static_cast<PClassPlayerPawn *>(PClass::FindClass(NAME_MagePlayer)); + PlayerClasses.Push(newclass); } else if (gameinfo.gametype == GAME_Strife) { - newclass.Type = PClass::FindClass (NAME_StrifePlayer); - PlayerClasses.Push (newclass); + newclass.Type = static_cast<PClassPlayerPawn *>(PClass::FindClass(NAME_StrifePlayer)); + PlayerClasses.Push(newclass); } else if (gameinfo.gametype == GAME_Chex) { - newclass.Type = PClass::FindClass (NAME_ChexPlayer); - PlayerClasses.Push (newclass); + newclass.Type = static_cast<PClassPlayerPawn *>(PClass::FindClass(NAME_ChexPlayer)); + PlayerClasses.Push(newclass); } } @@ -145,17 +145,13 @@ CCMD (addplayerclass) { if (ParsingKeyConf && argv.argc () > 1) { - const PClass *ti = PClass::FindClass (argv[1]); + PClassPlayerPawn *ti = dyn_cast<PClassPlayerPawn>(PClass::FindClass(argv[1])); - if (!ti) + if (ti == NULL) { Printf ("Unknown player class '%s'\n", argv[1]); } - else if (!ti->IsDescendantOf (RUNTIME_CLASS (APlayerPawn))) - { - Printf ("Invalid player class '%s'\n", argv[1]); - } - else if (ti->Meta.GetMetaString (APMETA_DisplayName) == NULL) + else if (ti->DisplayName.IsEmpty()) { Printf ("Missing displayname for player class '%s'\n", argv[1]); } @@ -180,7 +176,6 @@ CCMD (addplayerclass) arg++; } - PlayerClasses.Push (newclass); } } @@ -190,8 +185,7 @@ CCMD (playerclasses) { for (unsigned int i = 0; i < PlayerClasses.Size (); i++) { - Printf ("% 3d %s\n", i, - PlayerClasses[i].Type->Meta.GetMetaString (APMETA_DisplayName)); + Printf("% 3d %s\n", i, PlayerClasses[i].Type->DisplayName.GetChars()); } } @@ -396,6 +390,48 @@ int player_t::GetSpawnClass() return static_cast<APlayerPawn*>(GetDefaultByType(type))->SpawnMask; } +//=========================================================================== +// +// PClassPlayerPawn +// +//=========================================================================== + +IMPLEMENT_CLASS(PClassPlayerPawn) + +PClassPlayerPawn::PClassPlayerPawn() +{ + for (int i = 0; i < countof(HexenArmor); ++i) + { + HexenArmor[i] = 0; + } + ColorRangeStart = 0; + ColorRangeEnd = 0; +} + +void PClassPlayerPawn::Derive(PClass *newclass) +{ + assert(newclass->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); + Super::Derive(newclass); + PClassPlayerPawn *newp = static_cast<PClassPlayerPawn *>(newclass); + int i; + + newp->DisplayName = DisplayName; + newp->SoundClass = SoundClass; + newp->Face = Face; + newp->InvulMode = InvulMode; + newp->HealingRadiusType = HealingRadiusType; + newp->ColorRangeStart = ColorRangeStart; + newp->ColorRangeEnd = ColorRangeEnd; + for (i = 0; i < countof(HexenArmor); ++i) + { + newp->HexenArmor[i] = HexenArmor[i]; + } + for (i = 0; i < countof(Slot); ++i) + { + newp->Slot[i] = Slot[i]; + } +} + //=========================================================================== // // APlayerPawn @@ -908,8 +944,8 @@ const char *APlayerPawn::GetSoundClass () } // [GRB] - const char *sclass = GetClass ()->Meta.GetMetaString (APMETA_SoundClass); - return sclass != NULL ? sclass : "player"; + PClassPlayerPawn *pclass = GetClass(); + return pclass->SoundClass.IsNotEmpty() ? pclass->SoundClass : "player"; } //=========================================================================== @@ -1026,18 +1062,14 @@ void APlayerPawn::GiveDefaultInventory () // HexenArmor must always be the first item in the inventory because // it provides player class based protection that should not affect // any other protection item. - fixed_t hx[5]; - for(int i=0;i<5;i++) - { - hx[i] = GetClass()->Meta.GetMetaFixed(APMETA_Hexenarmor0+i); - } - GiveInventoryType (RUNTIME_CLASS(AHexenArmor)); + PClassPlayerPawn *myclass = GetClass(); + GiveInventoryType(RUNTIME_CLASS(AHexenArmor)); AHexenArmor *harmor = FindInventory<AHexenArmor>(); - harmor->Slots[4] = hx[0]; - harmor->SlotsIncrement[0] = hx[1]; - harmor->SlotsIncrement[1] = hx[2]; - harmor->SlotsIncrement[2] = hx[3]; - harmor->SlotsIncrement[3] = hx[4]; + harmor->Slots[4] = myclass->HexenArmor[0]; + for (int i = 0; i < 4; ++i) + { + harmor->SlotsIncrement[i] = myclass->HexenArmor[i + 1]; + } // BasicArmor must come right after that. It should not affect any // other protection item as well but needs to process the damage @@ -1049,7 +1081,7 @@ void APlayerPawn::GiveDefaultInventory () AddInventory (barmor); // Now add the items from the DECORATE definition - FDropItem *di = GetDropItems(); + DDropItem *di = GetDropItems(); while (di) { @@ -1060,14 +1092,14 @@ void APlayerPawn::GiveDefaultInventory () if (item != NULL) { item->Amount = clamp<int>( - item->Amount + (di->amount ? di->amount : ((AInventory *)item->GetDefault ())->Amount), + item->Amount + (di->Amount ? di->Amount : ((AInventory *)item->GetDefault ())->Amount), 0, item->MaxAmount); } else { item = static_cast<AInventory *>(Spawn (ti, 0,0,0, NO_REPLACE)); - item->ItemFlags|=IF_IGNORESKILL; // no skill multiplicators here - item->Amount = di->amount; + item->ItemFlags |= IF_IGNORESKILL; // no skill multiplicators here + item->Amount = di->Amount; if (item->IsKindOf (RUNTIME_CLASS (AWeapon))) { // To allow better control any weapon is emptied of @@ -1341,7 +1373,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SkullPop) // [GRB] Parameterized version if (spawntype == NULL || !spawntype->IsDescendantOf(RUNTIME_CLASS(APlayerChunk))) { - spawntype = PClass::FindActor("BloodySkull"); + spawntype = dyn_cast<PClassPlayerPawn>(PClass::FindClass("BloodySkull")); if (spawntype == NULL) return 0; } diff --git a/src/r_main.cpp b/src/r_main.cpp index 789388842..080628fe2 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -1064,7 +1064,7 @@ void R_SetupFrame (AActor *actor) { iview->nviewx = camera->x; iview->nviewy = camera->y; - iview->nviewz = camera->player ? camera->player->viewz : camera->z + camera->GetClass()->Meta.GetMetaFixed(AMETA_CameraHeight); + iview->nviewz = camera->player ? camera->player->viewz : camera->z + camera->GetCameraHeight(); viewsector = camera->Sector; r_showviewer = false; } diff --git a/src/r_things.cpp b/src/r_things.cpp index a2f18de5f..a9c683a70 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -442,7 +442,7 @@ void R_InitSkins (void) int lastlump; int aliasid; bool remove; - const PClass *basetype, *transtype; + PClassPlayerPawn *basetype, *transtype; key[sizeof(key)-1] = 0; i = PlayerClasses.Size () - 1; @@ -527,11 +527,11 @@ void R_InitSkins (void) else if (0 == stricmp (key, "game")) { if (gameinfo.gametype == GAME_Heretic) - basetype = PClass::FindClass (NAME_HereticPlayer); + basetype = static_cast<PClassPlayerPawn *>(PClass::FindClass (NAME_HereticPlayer)); else if (gameinfo.gametype == GAME_Strife) - basetype = PClass::FindClass (NAME_StrifePlayer); + basetype = static_cast<PClassPlayerPawn *>(PClass::FindClass (NAME_StrifePlayer)); else - basetype = PClass::FindClass (NAME_DoomPlayer); + basetype = static_cast<PClassPlayerPawn *>(PClass::FindClass (NAME_DoomPlayer)); transtype = basetype; @@ -539,7 +539,7 @@ void R_InitSkins (void) { if (gameinfo.gametype & GAME_DoomChex) { - transtype = PClass::FindClass (NAME_HereticPlayer); + transtype = static_cast<PClassPlayerPawn *>(PClass::FindClass (NAME_HereticPlayer)); skins[i].othergame = true; } else if (gameinfo.gametype != GAME_Heretic) @@ -558,7 +558,7 @@ void R_InitSkins (void) { if (gameinfo.gametype == GAME_Heretic) { - transtype = PClass::FindClass (NAME_DoomPlayer); + transtype = static_cast<PClassPlayerPawn *>(PClass::FindClass (NAME_DoomPlayer)); skins[i].othergame = true; } else if (!(gameinfo.gametype & GAME_DoomChex)) @@ -634,12 +634,12 @@ void R_InitSkins (void) { if (gameinfo.gametype & GAME_DoomChex) { - basetype = transtype = PClass::FindClass (NAME_DoomPlayer); + basetype = transtype = static_cast<PClassPlayerPawn *>(PClass::FindClass (NAME_DoomPlayer)); } else if (gameinfo.gametype == GAME_Heretic) { - basetype = PClass::FindClass (NAME_HereticPlayer); - transtype = PClass::FindClass (NAME_DoomPlayer); + basetype = static_cast<PClassPlayerPawn *>(PClass::FindClass (NAME_HereticPlayer)); + transtype = static_cast<PClassPlayerPawn *>(PClass::FindClass (NAME_DoomPlayer)); skins[i].othergame = true; } else @@ -650,17 +650,18 @@ void R_InitSkins (void) if (!remove) { - skins[i].range0start = transtype->Meta.GetMetaInt (APMETA_ColorRange) & 0xff; - skins[i].range0end = transtype->Meta.GetMetaInt (APMETA_ColorRange) >> 8; + skins[i].range0start = transtype->ColorRangeStart; + skins[i].range0end = transtype->ColorRangeEnd; remove = true; for (j = 0; j < (int)PlayerClasses.Size (); j++) { - const PClass *type = PlayerClasses[j].Type; + PClassPlayerPawn *type = PlayerClasses[j].Type; if (type->IsDescendantOf (basetype) && GetDefaultByType (type)->SpawnState->sprite == GetDefaultByType (basetype)->SpawnState->sprite && - type->Meta.GetMetaInt (APMETA_ColorRange) == basetype->Meta.GetMetaInt (APMETA_ColorRange)) + type->ColorRangeStart == basetype->ColorRangeStart && + type->ColorRangeEnd == basetype->ColorRangeEnd) { PlayerClasses[j].Skins.Push ((int)i); remove = false; @@ -871,9 +872,9 @@ void R_InitSprites () memset (skins, 0, sizeof(*skins) * numskins); for (i = 0; i < numskins; i++) { // Assume Doom skin by default - const PClass *type = PlayerClasses[0].Type; - skins[i].range0start = type->Meta.GetMetaInt (APMETA_ColorRange) & 255; - skins[i].range0end = type->Meta.GetMetaInt (APMETA_ColorRange) >> 8; + PClassPlayerPawn *type = PlayerClasses[0].Type; + skins[i].range0start = type->ColorRangeStart; + skins[i].range0end = type->ColorRangeEnd; skins[i].ScaleX = GetDefaultByType (type)->scaleX; skins[i].ScaleY = GetDefaultByType (type)->scaleY; } @@ -886,11 +887,11 @@ void R_InitSprites () // [GRB] Each player class has its own base skin for (i = 0; i < PlayerClasses.Size (); i++) { - const PClass *basetype = PlayerClasses[i].Type; - const char *pclassface = basetype->Meta.GetMetaString (APMETA_Face); + PClassPlayerPawn *basetype = PlayerClasses[i].Type; + FString pclassface = basetype->Face; strcpy (skins[i].name, "Base"); - if (pclassface == NULL || strcmp(pclassface, "None") == 0) + if (pclassface.IsEmpty() || strcmp(pclassface, "None") == 0) { skins[i].face[0] = 'S'; skins[i].face[1] = 'T'; @@ -901,8 +902,8 @@ void R_InitSprites () { strcpy(skins[i].face, pclassface); } - skins[i].range0start = basetype->Meta.GetMetaInt (APMETA_ColorRange) & 255; - skins[i].range0end = basetype->Meta.GetMetaInt (APMETA_ColorRange) >> 8; + skins[i].range0start = basetype->ColorRangeStart; + skins[i].range0end = basetype->ColorRangeEnd; skins[i].ScaleX = GetDefaultByType (basetype)->scaleX; skins[i].ScaleY = GetDefaultByType (basetype)->scaleY; skins[i].sprite = GetDefaultByType (basetype)->SpawnState->sprite; diff --git a/src/textures/textures.h b/src/textures/textures.h index 4bfffe54b..ab4595bf0 100644 --- a/src/textures/textures.h +++ b/src/textures/textures.h @@ -7,7 +7,7 @@ class FBitmap; struct FRemapTable; struct FCopyInfo; class FScanner; -class PClass; +class PClassInventory; class FArchive; // Texture IDs @@ -18,7 +18,7 @@ class FTextureID { friend class FTextureManager; friend FArchive &operator<< (FArchive &arc, FTextureID &tex); - friend FTextureID GetHUDIcon(const PClass *cls); + friend FTextureID GetHUDIcon(PClassInventory *cls); friend void R_InitSpriteDefs (); public: diff --git a/src/thingdef/olddecorations.cpp b/src/thingdef/olddecorations.cpp index 44afb3351..3fe2f6e39 100644 --- a/src/thingdef/olddecorations.cpp +++ b/src/thingdef/olddecorations.cpp @@ -256,7 +256,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) { extra.DeathHeight = ((AActor*)(type->Defaults))->height; } - type->Meta.SetMetaFixed (AMETA_DeathHeight, extra.DeathHeight); + type->DeathHeight = extra.DeathHeight; } bag.statedef.SetStateLabel("Death", &type->OwnedStates[extra.DeathStart]); } @@ -294,7 +294,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) } if (extra.BurnHeight == 0) extra.BurnHeight = ((AActor*)(type->Defaults))->height; - type->Meta.SetMetaFixed (AMETA_BurnHeight, extra.BurnHeight); + type->BurnHeight = extra.BurnHeight; bag.statedef.SetStateLabel("Burn", &type->OwnedStates[extra.FireDeathStart]); } @@ -475,18 +475,18 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, else if (def == DEF_Projectile && sc.Compare ("ExplosionRadius")) { sc.MustGetNumber (); - bag.Info->Meta.SetMetaInt(ACMETA_ExplosionRadius, sc.Number); + bag.Info->ExplosionRadius = sc.Number; extra.bExplosive = true; } else if (def == DEF_Projectile && sc.Compare ("ExplosionDamage")) { sc.MustGetNumber (); - bag.Info->Meta.SetMetaInt(ACMETA_ExplosionDamage, sc.Number); + bag.Info->ExplosionDamage = sc.Number; extra.bExplosive = true; } else if (def == DEF_Projectile && sc.Compare ("DoNotHurtShooter")) { - bag.Info->Meta.SetMetaInt(ACMETA_DontHurtShooter, true); + bag.Info->DontHurtShooter = true; } else if (def == DEF_Projectile && sc.Compare ("Damage")) { @@ -571,7 +571,7 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, else if (def == DEF_Pickup && sc.Compare ("PickupMessage")) { sc.MustGetString (); - bag.Info->Meta.SetMetaString(AIMETA_PickupMessage, sc.String); + static_cast<PClassInventory *>(bag.Info)->PickupMessage = sc.String; } else if (def == DEF_Pickup && sc.Compare ("Respawns")) { diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 00694457c..3d4106050 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -208,17 +208,7 @@ void FinishActor(const FScriptPosition &sc, PClassActor *info, Baggage &bag) bag.statedef.MakeStateDefines(NULL); if (bag.DropItemSet) { - if (bag.DropItemList == NULL) - { - if (info->Meta.GetMetaInt (ACMETA_DropItems) != 0) - { - info->Meta.SetMetaInt (ACMETA_DropItems, 0); - } - } - else - { - info->Meta.SetMetaInt (ACMETA_DropItems, StoreDropItemChain(bag.DropItemList)); - } + info->DropItems = bag.DropItemList; } if (info->IsDescendantOf (RUNTIME_CLASS(AInventory))) { diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index 31b1d1274..a430ae878 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -152,7 +152,7 @@ extern FStateExpressions StateParams; // Extra info maintained while defining an actor. // //========================================================================== -struct FDropItem; +class DDropItem; struct Baggage { @@ -166,7 +166,7 @@ struct Baggage int Lumpnum; FStateDefinitions statedef; - FDropItem *DropItemList; + DDropItem *DropItemList; FScriptPosition ScriptPosition; }; @@ -235,13 +235,6 @@ enum { ACMETA_BASE = 0x83000, ACMETA_DropItems, // Int (index into DropItemList) - ACMETA_ExplosionDamage, - ACMETA_ExplosionRadius, - ACMETA_DontHurtShooter, - ACMETA_MeleeSound, - ACMETA_MeleeDamage, - ACMETA_MissileName, - ACMETA_MissileHeight, }; diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index a5d7ef98c..c501daf04 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -213,8 +213,8 @@ static void DoAttack (AActor *self, bool domelee, bool domissile, DEFINE_ACTION_FUNCTION(AActor, A_MeleeAttack) { PARAM_ACTION_PROLOGUE; - int MeleeDamage = self->GetClass()->Meta.GetMetaInt(ACMETA_MeleeDamage, 0); - FSoundID MeleeSound = self->GetClass()->Meta.GetMetaInt(ACMETA_MeleeSound, 0); + int MeleeDamage = self->GetClass()->MeleeDamage; + FSoundID MeleeSound = self->GetClass()->MeleeSound; DoAttack(self, true, false, MeleeDamage, MeleeSound, NULL, 0); return 0; } @@ -222,8 +222,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_MeleeAttack) DEFINE_ACTION_FUNCTION(AActor, A_MissileAttack) { PARAM_ACTION_PROLOGUE; - const PClass *MissileType = PClass::FindClass(ENamedName(self->GetClass()->Meta.GetMetaInt(ACMETA_MissileName, NAME_None))); - fixed_t MissileHeight = self->GetClass()->Meta.GetMetaFixed(ACMETA_MissileHeight, 32*FRACUNIT); + PClassActor *MissileType = PClass::FindActor(self->GetClass()->MissileName); + fixed_t MissileHeight = self->GetClass()->MissileHeight; DoAttack(self, false, true, 0, 0, MissileType, MissileHeight); return 0; } @@ -231,10 +231,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_MissileAttack) DEFINE_ACTION_FUNCTION(AActor, A_ComboAttack) { PARAM_ACTION_PROLOGUE; - int MeleeDamage = self->GetClass()->Meta.GetMetaInt(ACMETA_MeleeDamage, 0); - FSoundID MeleeSound = self->GetClass()->Meta.GetMetaInt(ACMETA_MeleeSound, 0); - const PClass *MissileType = PClass::FindClass(ENamedName(self->GetClass()->Meta.GetMetaInt(ACMETA_MissileName, NAME_None))); - fixed_t MissileHeight = self->GetClass()->Meta.GetMetaFixed(ACMETA_MissileHeight, 32*FRACUNIT); + int MeleeDamage = self->GetClass()->MeleeDamage; + FSoundID MeleeSound = self->GetClass()->MeleeSound; + PClassActor *MissileType = PClass::FindActor(self->GetClass()->MissileName); + fixed_t MissileHeight = self->GetClass()->MissileHeight; DoAttack(self, true, true, MeleeDamage, MeleeSound, MissileType, MissileHeight); return 0; } @@ -622,9 +622,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode) if (damage < 0) // get parameters from metadata { - damage = self->GetClass()->Meta.GetMetaInt (ACMETA_ExplosionDamage, 128); - distance = self->GetClass()->Meta.GetMetaInt (ACMETA_ExplosionRadius, damage); - hurtSource = !self->GetClass()->Meta.GetMetaInt (ACMETA_DontHurtShooter); + damage = self->GetClass()->ExplosionDamage; + distance = self->GetClass()->ExplosionRadius; + if (distance < 0) + { + distance = damage; + } + hurtSource = !self->GetClass()->DontHurtShooter; alert = false; } else diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index 9690756b5..1a0c0b062 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -74,7 +74,7 @@ // Gets a class pointer and performs an error check for correct type // //========================================================================== -static PClassActor *FindClassTentative(const char *name, const char *ancestor) +static PClassActor *FindClassTentative(const char *name, PClass *ancestor) { // "" and "none" mean 'no class' if (name == NULL || *name == 0 || !stricmp(name, "none")) @@ -82,16 +82,26 @@ static PClassActor *FindClassTentative(const char *name, const char *ancestor) return NULL; } - PClass *anc = PClass::FindClass(ancestor); - assert(anc != NULL); // parent classes used here should always be natively defined - PClass *cls = anc->FindClassTentative(name); - assert (cls != NULL); // cls can not ne NULL here - if (!cls->IsDescendantOf(anc)) + PClass *cls = ancestor->FindClassTentative(name); + assert(cls != NULL); // cls can not be NULL here + if (!cls->IsDescendantOf(ancestor)) { I_Error("%s does not inherit from %s\n", name, ancestor); } return static_cast<PClassActor *>(cls); } +static AAmmo::MetaClass *FindClassTentativeAmmo(const char *name) +{ + return static_cast<AAmmo::MetaClass *>(FindClassTentative(name, RUNTIME_CLASS(AAmmo))); +} +static AWeapon::MetaClass *FindClassTentativeWeapon(const char *name) +{ + return static_cast<AWeapon::MetaClass *>(FindClassTentative(name, RUNTIME_CLASS(AWeapon))); +} +static APowerup::MetaClass *FindClassTentativePowerup(const char *name) +{ + return static_cast<APowerup::MetaClass *>(FindClassTentative(name, RUNTIME_CLASS(APowerup))); +} //=========================================================================== // @@ -144,7 +154,7 @@ void HandleDeprecatedFlags(AActor *defaults, PClassActor *info, bool set, int in case DEPF_PICKUPFLASH: if (set) { - static_cast<AInventory*>(defaults)->PickupFlash = FindClassTentative("PickupFlash", "Actor"); + static_cast<AInventory*>(defaults)->PickupFlash = FindClassTentative("PickupFlash", RUNTIME_CLASS(AActor)); } else { @@ -293,10 +303,6 @@ DEFINE_PROPERTY(skip_super, 0, Actor) } memcpy (defaults, GetDefault<AActor>(), sizeof(AActor)); - if (bag.DropItemList != NULL) - { - FreeDropItemChain (bag.DropItemList); - } ResetBaggage (&bag, RUNTIME_CLASS(AActor)); } @@ -324,7 +330,8 @@ DEFINE_PROPERTY(health, I, Actor) DEFINE_PROPERTY(gibhealth, I, Actor) { PROP_INT_PARM(id, 0); - info->Meta.SetMetaInt (AMETA_GibHealth, id); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast<PClassActor *>(info)->GibHealth = id; } //========================================================================== @@ -333,7 +340,8 @@ DEFINE_PROPERTY(gibhealth, I, Actor) DEFINE_PROPERTY(woundhealth, I, Actor) { PROP_INT_PARM(id, 0); - info->Meta.SetMetaInt (AMETA_WoundHealth, id); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast<PClassActor *>(info)->WoundHealth = id; } //========================================================================== @@ -556,7 +564,8 @@ DEFINE_PROPERTY(activesound, S, Actor) DEFINE_PROPERTY(howlsound, S, Actor) { PROP_STRING_PARM(str, 0); - info->Meta.SetMetaInt (AMETA_HowlSound, S_FindSound(str)); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast<PClassActor *>(info)->HowlSound = str; } //========================================================================== @@ -573,20 +582,20 @@ DEFINE_PROPERTY(dropitem, S_i_i, Actor) bag.DropItemList = NULL; } - FDropItem *di = new FDropItem; + DDropItem *di = new DDropItem; - di->Name =type; - di->probability=255; - di->amount=-1; + di->Name = type; + di->Probability = 255; + di->Amount = -1; if (PROP_PARM_COUNT > 1) { PROP_INT_PARM(prob, 1); - di->probability = prob; + di->Probability = prob; if (PROP_PARM_COUNT > 2) { PROP_INT_PARM(amt, 2); - di->amount = amt; + di->Amount = amt; } } di->Next = bag.DropItemList; @@ -637,7 +646,8 @@ DEFINE_PROPERTY(alpha, F, Actor) DEFINE_PROPERTY(obituary, S, Actor) { PROP_STRING_PARM(str, 0); - info->Meta.SetMetaString (AMETA_Obituary, str); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast<PClassActor *>(info)->Obituary = str; } //========================================================================== @@ -646,7 +656,8 @@ DEFINE_PROPERTY(obituary, S, Actor) DEFINE_PROPERTY(hitobituary, S, Actor) { PROP_STRING_PARM(str, 0); - info->Meta.SetMetaString (AMETA_HitObituary, str); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast<PClassActor *>(info)->HitObituary = str; } //========================================================================== @@ -654,7 +665,8 @@ DEFINE_PROPERTY(hitobituary, S, Actor) //========================================================================== DEFINE_PROPERTY(donthurtshooter, 0, Actor) { - info->Meta.SetMetaInt (ACMETA_DontHurtShooter, true); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast<PClassActor *>(info)->DontHurtShooter = true; } //========================================================================== @@ -663,7 +675,8 @@ DEFINE_PROPERTY(donthurtshooter, 0, Actor) DEFINE_PROPERTY(explosionradius, I, Actor) { PROP_INT_PARM(id, 0); - info->Meta.SetMetaInt (ACMETA_ExplosionRadius, id); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast<PClassActor *>(info)->ExplosionRadius = id; } //========================================================================== @@ -672,7 +685,8 @@ DEFINE_PROPERTY(explosionradius, I, Actor) DEFINE_PROPERTY(explosiondamage, I, Actor) { PROP_INT_PARM(id, 0); - info->Meta.SetMetaInt (ACMETA_ExplosionDamage, id); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast<PClassActor *>(info)->ExplosionDamage = id; } //========================================================================== @@ -681,9 +695,8 @@ DEFINE_PROPERTY(explosiondamage, I, Actor) DEFINE_PROPERTY(deathheight, F, Actor) { PROP_FIXED_PARM(h, 0); - // AActor::Die() uses a height of 0 to mean "cut the height to 1/4", - // so if a height of 0 is desired, store it as -1. - info->Meta.SetMetaFixed (AMETA_DeathHeight, h <= 0 ? -1 : h); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast<PClassActor *>(info)->DeathHeight = MAX(0, h); } //========================================================================== @@ -692,8 +705,8 @@ DEFINE_PROPERTY(deathheight, F, Actor) DEFINE_PROPERTY(burnheight, F, Actor) { PROP_FIXED_PARM(h, 0); - // The note above for AMETA_DeathHeight also applies here. - info->Meta.SetMetaFixed (AMETA_BurnHeight, h <= 0 ? -1 : h); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast<PClassActor *>(info)->BurnHeight = MAX(0, h); } //========================================================================== @@ -720,7 +733,8 @@ DEFINE_PROPERTY(meleethreshold, F, Actor) DEFINE_PROPERTY(meleedamage, I, Actor) { PROP_INT_PARM(id, 0); - info->Meta.SetMetaInt (ACMETA_MeleeDamage, id); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast<PClassActor *>(info)->MeleeDamage = id; } //========================================================================== @@ -738,7 +752,8 @@ DEFINE_PROPERTY(meleerange, F, Actor) DEFINE_PROPERTY(meleesound, S, Actor) { PROP_STRING_PARM(str, 0); - info->Meta.SetMetaInt (ACMETA_MeleeSound, S_FindSound(str)); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast<PClassActor *>(info)->MeleeSound = str; } //========================================================================== @@ -747,7 +762,8 @@ DEFINE_PROPERTY(meleesound, S, Actor) DEFINE_PROPERTY(missiletype, S, Actor) { PROP_STRING_PARM(str, 0); - info->Meta.SetMetaInt (ACMETA_MissileName, FName(str)); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast<PClassActor *>(info)->MissileName = str; } //========================================================================== @@ -756,7 +772,8 @@ DEFINE_PROPERTY(missiletype, S, Actor) DEFINE_PROPERTY(missileheight, F, Actor) { PROP_FIXED_PARM(id, 0); - info->Meta.SetMetaFixed (ACMETA_MissileHeight, id); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast<PClassActor *>(info)->MissileHeight = id; } //========================================================================== @@ -826,7 +843,8 @@ DEFINE_PROPERTY(bloodcolor, C, Actor) PalEntry pe = color; pe.a = CreateBloodTranslation(pe); - info->Meta.SetMetaInt (AMETA_BloodColor, pe); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast<PClassActor *>(info)->BloodColor = pe; } @@ -839,23 +857,26 @@ DEFINE_PROPERTY(bloodtype, Sss, Actor) PROP_STRING_PARM(str1, 1) PROP_STRING_PARM(str2, 2) + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + PClassActor *ainfo = static_cast<PClassActor *>(info); + FName blood = str; // normal blood - info->Meta.SetMetaInt (AMETA_BloodType, blood); + ainfo->BloodType = blood; if (PROP_PARM_COUNT > 1) { blood = str1; } // blood splatter - info->Meta.SetMetaInt (AMETA_BloodType2, blood); + ainfo->BloodType2 = blood; if (PROP_PARM_COUNT > 2) { blood = str2; } // axe blood - info->Meta.SetMetaInt (AMETA_BloodType3, blood); + ainfo->BloodType3 = blood; } //========================================================================== @@ -1000,7 +1021,8 @@ DEFINE_PROPERTY(maxdropoffheight, F, Actor) DEFINE_PROPERTY(poisondamage, I, Actor) { PROP_INT_PARM(i, 0); - info->Meta.SetMetaInt (AMETA_PoisonDamage, i); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast<PClassActor *>(info)->PoisonDamage = i; } //========================================================================== @@ -1009,7 +1031,8 @@ DEFINE_PROPERTY(poisondamage, I, Actor) DEFINE_PROPERTY(fastspeed, F, Actor) { PROP_FIXED_PARM(i, 0); - info->Meta.SetMetaFixed (AMETA_FastSpeed, i); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast<PClassActor *>(info)->FastSpeed = i; } //========================================================================== @@ -1018,7 +1041,8 @@ DEFINE_PROPERTY(fastspeed, F, Actor) DEFINE_PROPERTY(radiusdamagefactor, F, Actor) { PROP_FIXED_PARM(i, 0); - info->Meta.SetMetaFixed (AMETA_RDFactor, i); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast<PClassActor *>(info)->RDFactor = i; } //========================================================================== @@ -1027,7 +1051,8 @@ DEFINE_PROPERTY(radiusdamagefactor, F, Actor) DEFINE_PROPERTY(cameraheight, F, Actor) { PROP_FIXED_PARM(i, 0); - info->Meta.SetMetaFixed (AMETA_CameraHeight, i); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast<PClassActor *>(info)->CameraHeight = i; } //========================================================================== @@ -1135,7 +1160,8 @@ DEFINE_CLASS_PROPERTY(backpackmaxamount, I, Ammo) DEFINE_CLASS_PROPERTY(dropamount, I, Ammo) { PROP_INT_PARM(i, 0); - info->Meta.SetMetaInt (AIMETA_DropAmount, i); + assert(info->IsKindOf(RUNTIME_CLASS(PClassAmmo))); + static_cast<PClassAmmo *>(info)->DropAmount = i; } //========================================================================== @@ -1317,7 +1343,7 @@ DEFINE_CLASS_PROPERTY(defmaxamount, 0, Inventory) DEFINE_CLASS_PROPERTY(pickupflash, S, Inventory) { PROP_STRING_PARM(str, 0); - defaults->PickupFlash = FindClassTentative(str, "Actor"); + defaults->PickupFlash = FindClassTentative(str, RUNTIME_CLASS(AActor)); } //========================================================================== @@ -1326,7 +1352,8 @@ DEFINE_CLASS_PROPERTY(pickupflash, S, Inventory) DEFINE_CLASS_PROPERTY(pickupmessage, T, Inventory) { PROP_STRING_PARM(str, 0); - info->Meta.SetMetaString(AIMETA_PickupMessage, str); + assert(info->IsKindOf(RUNTIME_CLASS(PClassInventory))); + static_cast<PClassInventory *>(info)->PickupMessage = str; } //========================================================================== @@ -1369,7 +1396,8 @@ DEFINE_CLASS_PROPERTY(usesound, S, Inventory) DEFINE_CLASS_PROPERTY(givequest, I, Inventory) { PROP_INT_PARM(i, 0); - info->Meta.SetMetaInt(AIMETA_GiveQuest, i); + assert(info->IsKindOf(RUNTIME_CLASS(PClassInventory))); + static_cast<PClassInventory *>(info)->GiveQuest = i; } //========================================================================== @@ -1379,8 +1407,9 @@ DEFINE_CLASS_PROPERTY(lowmessage, IT, Health) { PROP_INT_PARM(i, 0); PROP_STRING_PARM(str, 1); - info->Meta.SetMetaInt(AIMETA_LowHealth, i); - info->Meta.SetMetaString(AIMETA_LowHealthMessage, str); + assert(info->IsKindOf(RUNTIME_CLASS(PClassHealth))); + static_cast<PClassHealth *>(info)->LowHealth = i; + static_cast<PClassHealth *>(info)->LowHealthMessage = str; } //========================================================================== @@ -1407,7 +1436,8 @@ DEFINE_CLASS_PROPERTY(number, I, PuzzleItem) DEFINE_CLASS_PROPERTY(failmessage, T, PuzzleItem) { PROP_STRING_PARM(str, 0); - info->Meta.SetMetaString(AIMETA_PuzzFailMessage, str); + assert(info->IsKindOf(RUNTIME_CLASS(PClassPuzzleItem))); + static_cast<PClassPuzzleItem *>(info)->PuzzFailMessage = str; } //========================================================================== @@ -1444,7 +1474,7 @@ DEFINE_CLASS_PROPERTY(ammotype, S, Weapon) { PROP_STRING_PARM(str, 0); if (!stricmp(str, "none") || *str == 0) defaults->AmmoType1 = NULL; - else defaults->AmmoType1 = FindClassTentative(str, "Ammo"); + else defaults->AmmoType1 = FindClassTentativeAmmo(str); } //========================================================================== @@ -1454,7 +1484,7 @@ DEFINE_CLASS_PROPERTY(ammotype1, S, Weapon) { PROP_STRING_PARM(str, 0); if (!stricmp(str, "none") || *str == 0) defaults->AmmoType1 = NULL; - else defaults->AmmoType1 = FindClassTentative(str, "Ammo"); + else defaults->AmmoType1 = FindClassTentativeAmmo(str); } //========================================================================== @@ -1464,7 +1494,7 @@ DEFINE_CLASS_PROPERTY(ammotype2, S, Weapon) { PROP_STRING_PARM(str, 0); if (!stricmp(str, "none") || *str == 0) defaults->AmmoType1 = NULL; - else defaults->AmmoType2 = FindClassTentative(str, "Ammo"); + else defaults->AmmoType2 = FindClassTentativeAmmo(str); } //========================================================================== @@ -1535,7 +1565,7 @@ DEFINE_CLASS_PROPERTY(selectionorder, I, Weapon) DEFINE_CLASS_PROPERTY(sisterweapon, S, Weapon) { PROP_STRING_PARM(str, 0); - defaults->SisterWeaponType = FindClassTentative(str, "Weapon"); + defaults->SisterWeaponType = FindClassTentativeWeapon(str); } //========================================================================== @@ -1562,7 +1592,8 @@ DEFINE_CLASS_PROPERTY(yadjust, F, Weapon) DEFINE_CLASS_PROPERTY(slotnumber, I, Weapon) { PROP_INT_PARM(i, 0); - info->Meta.SetMetaInt(AWMETA_SlotNumber, i); + assert(info->IsKindOf(RUNTIME_CLASS(PClassWeapon))); + static_cast<PClassWeapon *>(info)->SlotNumber = i; } //========================================================================== @@ -1571,7 +1602,8 @@ DEFINE_CLASS_PROPERTY(slotnumber, I, Weapon) DEFINE_CLASS_PROPERTY(slotpriority, F, Weapon) { PROP_FIXED_PARM(i, 0); - info->Meta.SetMetaFixed(AWMETA_SlotPriority, i); + assert(info->IsKindOf(RUNTIME_CLASS(PClassWeapon))); + static_cast<PClassWeapon *>(info)->SlotPriority = i; } //========================================================================== @@ -1589,7 +1621,7 @@ DEFINE_CLASS_PROPERTY(number, I, WeaponPiece) DEFINE_CLASS_PROPERTY(weapon, S, WeaponPiece) { PROP_STRING_PARM(str, 0); - defaults->WeaponClass = FindClassTentative(str, "Weapon"); + defaults->WeaponClass = FindClassTentativeWeapon(str); } //========================================================================== @@ -1777,7 +1809,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, type, S, PowerupGiver) { FString st; st.Format("%s%s", strnicmp(str, "power", 5)? "Power" : "", str); - cls = FindClassTentative(st, "Powerup"); + cls = FindClassTentativePowerup(st); } defaults->PowerupType = cls; @@ -1795,7 +1827,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, type, S, PowerupGiver) DEFINE_CLASS_PROPERTY_PREFIX(player, displayname, S, PlayerPawn) { PROP_STRING_PARM(str, 0); - info->Meta.SetMetaString (APMETA_DisplayName, str); + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); + static_cast<PClassPlayerPawn *>(info)->DisplayName = str; } //========================================================================== @@ -1807,7 +1840,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, soundclass, S, PlayerPawn) FString tmp = str; tmp.ReplaceChars (' ', '_'); - info->Meta.SetMetaString (APMETA_SoundClass, tmp); + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); + static_cast<PClassPlayerPawn *>(info)->SoundClass = tmp; } //========================================================================== @@ -1838,7 +1872,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, face, S, PlayerPawn) tmp.GetChars(), info->TypeName.GetChars ()); } - info->Meta.SetMetaString (APMETA_Face, tmp); + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); + static_cast<PClassPlayerPawn *>(info)->Face = tmp; } //========================================================================== @@ -1852,7 +1887,9 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorrange, I_I, PlayerPawn) if (start > end) swap (start, end); - info->Meta.SetMetaInt (APMETA_ColorRange, (start & 255) | ((end & 255) << 8)); + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); + static_cast<PClassPlayerPawn *>(info)->ColorRangeStart = start; + static_cast<PClassPlayerPawn *>(info)->ColorRangeEnd = end; } //========================================================================== @@ -2036,15 +2073,15 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn) bag.DropItemList = NULL; } - FDropItem * di=new FDropItem; + DDropItem *di = new DDropItem; di->Name = str; - di->probability = 255; - di->amount = 1; + di->Probability = 255; + di->Amount = 1; if (PROP_PARM_COUNT > 1) { PROP_INT_PARM(amt, 1); - di->amount = amt; + di->Amount = amt; } di->Next = bag.DropItemList; bag.DropItemList = di; @@ -2056,7 +2093,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn) DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn) { PROP_STRING_PARM(str, 0); - info->Meta.SetMetaInt (APMETA_InvulMode, (FName)str); + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); + static_cast<PClassPlayerPawn *>(info)->InvulMode = str; } //========================================================================== @@ -2065,7 +2103,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn) DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn) { PROP_STRING_PARM(str, 0); - info->Meta.SetMetaInt (APMETA_HealingRadius, (FName)str); + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); + static_cast<PClassPlayerPawn *>(info)->HealingRadiusType = str; } //========================================================================== @@ -2073,10 +2112,11 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn) //========================================================================== DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn) { - for (int i=0;i<5;i++) + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); + for (int i = 0; i < 5; i++) { PROP_FIXED_PARM(val, i); - info->Meta.SetMetaFixed (APMETA_Hexenarmor0+i, val); + static_cast<PClassPlayerPawn *>(info)->HexenArmor[i] = val; } } @@ -2087,6 +2127,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, weaponslot, ISsssssssssssssssssssssssssssss { PROP_INT_PARM(slot, 0); + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); if (slot < 0 || slot > 9) { I_Error("Slot must be between 0 and 9."); @@ -2100,7 +2141,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, weaponslot, ISsssssssssssssssssssssssssssss PROP_STRING_PARM(str, i); weapons << ' ' << str; } - info->Meta.SetMetaString(APMETA_Slot0 + slot, &weapons[1]); + static_cast<PClassPlayerPawn *>(info)->Slot[slot] = &weapons[1]; } } From 61d75b7caebfbb395b4a5de5fd684f5a4754872d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers <coelckers@zdoom.fake> Date: Fri, 26 Mar 2010 08:38:57 +0000 Subject: [PATCH 026/232] - fixed: Handling of empty pickup messages was wrong. The old metadata code made a distinction between an empty string and no string. To restore the original behavior the default initialization of the pickup message is now done in the DECORATE definition of Inventory. SVN r2244 (scripting) --- src/g_shared/a_pickups.cpp | 4 +--- wadsrc/static/actors/shared/inventory.txt | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index b64eaafea..8d895bb68 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -1005,9 +1005,7 @@ void AInventory::DoPickupSpecial (AActor *toucher) const char *AInventory::PickupMessage () { - FString message = GetClass()->PickupMessage; - - return message.IsNotEmpty() ? message : "You got a pickup"; + return GetClass()->PickupMessage; } //=========================================================================== diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt index 6aa43a55f..c527db26b 100644 --- a/wadsrc/static/actors/shared/inventory.txt +++ b/wadsrc/static/actors/shared/inventory.txt @@ -5,6 +5,7 @@ ACTOR Inventory native Inventory.InterHubAmount 1 Inventory.UseSound "misc/invuse" Inventory.PickupSound "misc/i_pkup" + Inventory.PickupMessage "You got a pickup." action native A_JumpIfNoAmmo(state label); action native A_CustomPunch(int damage, bool norandom = false, bool useammo = true, class<Actor> pufftype = "BulletPuff", float range = 0); From e553f9a34fa026b493b5bedf281e9f0753576142 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers <coelckers@zdoom.fake> Date: Fri, 26 Mar 2010 08:53:16 +0000 Subject: [PATCH 027/232] - removed some redundant initializations from PClassActor constructor. - Removed GibHealth function and integrated it into AActor::GetGibHealth. SVN r2245 (scripting) --- src/info.cpp | 2 -- src/p_interaction.cpp | 11 +++-------- src/p_mobj.cpp | 2 +- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/info.cpp b/src/info.cpp index 652e1c1aa..f4da5bf1f 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -176,8 +176,6 @@ PClassActor::PClassActor() DamageFactors = NULL; PainChances = NULL; - Obituary = Obituary; - HitObituary = HitObituary; DeathHeight = -1; BurnHeight = -1; GibHealth = INT_MIN; diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 176309f44..3ff9b02bd 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -314,15 +314,10 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker) // EXTERN_CVAR (Int, fraglimit) -static int GibHealth(AActor *actor) -{ - return -abs(actor->GetGibHealth()); -} - void AActor::Die (AActor *source, AActor *inflictor) { // Handle possible unmorph on death - bool wasgibbed = (health < GibHealth(this)); + bool wasgibbed = (health < GetGibHealth()); AActor *realthis = NULL; int realstyle = 0; @@ -333,7 +328,7 @@ void AActor::Die (AActor *source, AActor *inflictor) { if (wasgibbed) { - int realgibhealth = GibHealth(realthis); + int realgibhealth = realthis->GetGibHealth(); if (realthis->health >= realgibhealth) { realthis->health = realgibhealth -1; // if morphed was gibbed, so must original be (where allowed) @@ -661,7 +656,7 @@ void AActor::Die (AActor *source, AActor *inflictor) { int flags4 = inflictor == NULL ? 0 : inflictor->flags4; - int gibhealth = GibHealth(this); + int gibhealth = GetGibHealth(); // Don't pass on a damage type this actor cannot handle. // (most importantly, prevent barrels from passing on ice damage.) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 9c0ddbdb3..caed7d7b9 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5561,7 +5561,7 @@ int AActor::GetGibHealth() const if (gibhealth != INT_MIN) { - return gibhealth; + return -abs(gibhealth); } else if (gameinfo.gametype & GAME_DoomChex) { From d87d2c731f2665533f3aa39c71c61cf364f7c097 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 30 Mar 2010 04:11:16 +0000 Subject: [PATCH 028/232] - Use a map for symbol tables instead of an array. SVN r2258 (scripting) --- src/dobject.cpp | 7 ++-- src/dobjtype.cpp | 70 +++++++++----------------------------- src/dobjtype.h | 4 ++- src/zscript/zcc_parser.cpp | 4 +++ 4 files changed, 28 insertions(+), 57 deletions(-) diff --git a/src/dobject.cpp b/src/dobject.cpp index 2f5fd0cac..405c96514 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -389,9 +389,12 @@ void DObject::SerializeUserVars(FArchive &arc) // Write all user variables. for (; symt != NULL; symt = symt->ParentSymbolTable) { - for (unsigned i = 0; i < symt->Symbols.Size(); ++i) + PSymbolTable::MapType::Iterator it(symt->Symbols); + PSymbolTable::MapType::Pair *pair; + + while (it.NextPair(pair)) { - PSymbol *sym = symt->Symbols[i]; + PSymbol *sym = pair->Value; if (sym->SymbolType == SYM_Variable) { PSymbolVariable *var = static_cast<PSymbolVariable *>(sym); diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 4e02dbba7..1649ca46a 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -481,11 +481,16 @@ PSymbolTable::~PSymbolTable () size_t PSymbolTable::MarkSymbols() { - for (unsigned int i = 0; i < Symbols.Size(); ++i) + size_t count = 0; + MapType::Iterator it(Symbols); + MapType::Pair *pair; + + while (it.NextPair(pair)) { - GC::Mark(Symbols[i]); + GC::Mark(pair->Value); + count++; } - return Symbols.Size() * sizeof(Symbols[0]); + return count * sizeof(Symbols[0]); } void PSymbolTable::ReleaseSymbols() @@ -502,64 +507,21 @@ void PSymbolTable::SetParentTable (PSymbolTable *parent) PSymbol *PSymbolTable::FindSymbol (FName symname, bool searchparents) const { - int min, max; - - min = 0; - max = (int)Symbols.Size() - 1; - - while (min <= max) + PSymbol * const *value = Symbols.CheckKey(symname); + if (value == NULL && searchparents && ParentSymbolTable != NULL) { - unsigned int mid = (min + max) / 2; - PSymbol *sym = Symbols[mid]; - - if (sym->SymbolName == symname) - { - return sym; - } - else if (sym->SymbolName < symname) - { - min = mid + 1; - } - else - { - max = mid - 1; - } + return ParentSymbolTable->FindSymbol(symname, searchparents); } - if (searchparents && ParentSymbolTable != NULL) - { - return ParentSymbolTable->FindSymbol (symname, true); - } - return NULL; + return value != NULL ? *value : NULL; } PSymbol *PSymbolTable::AddSymbol (PSymbol *sym) { - // Insert it in sorted order. - int min, max, mid; - - min = 0; - max = (int)Symbols.Size() - 1; - - while (min <= max) + // Symbols that already exist are not inserted. + if (Symbols.CheckKey(sym->SymbolName) != NULL) { - mid = (min + max) / 2; - PSymbol *tsym = Symbols[mid]; - - if (tsym->SymbolName == sym->SymbolName) - { // A symbol with this name already exists in the table - return NULL; - } - else if (tsym->SymbolName < sym->SymbolName) - { - min = mid + 1; - } - else - { - max = mid - 1; - } + return NULL; } - - // Good. The symbol is not in the table yet. - Symbols.Insert (MAX(min, max), sym); + Symbols.Insert(sym->SymbolName, sym); return sym; } diff --git a/src/dobjtype.h b/src/dobjtype.h index 063c52a2c..1090d659e 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -141,8 +141,10 @@ struct PSymbolTable void ReleaseSymbols(); private: + typedef TMap<FName, PSymbol *> MapType; + PSymbolTable *ParentSymbolTable; - TArray<PSymbol *> Symbols; + MapType Symbols; friend class DObject; }; diff --git a/src/zscript/zcc_parser.cpp b/src/zscript/zcc_parser.cpp index 8e3abe942..fc1a0b35e 100644 --- a/src/zscript/zcc_parser.cpp +++ b/src/zscript/zcc_parser.cpp @@ -241,8 +241,10 @@ static void DoParse(const char *filename) parser = ZCCParseAlloc(malloc); failed = false; +#ifdef _DEBUG FILE *f = fopen("trace.txt", "w"); ZCCParseTrace(f, ""); +#endif while (sc.GetToken()) { if (sc.TokenType == TK_StringConst) @@ -294,10 +296,12 @@ static void DoParse(const char *filename) ZCCParse(parser, ZCC_EOF, value, &sc); ZCCParse(parser, 0, value, &sc); ZCCParseFree(parser, free); +#ifdef _DEBUG if (f != NULL) { fclose(f); } +#endif } CCMD(parse) From cc2ed53c49d70c18c06c0f8f5a383d3a19c285c4 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 31 Mar 2010 02:43:55 +0000 Subject: [PATCH 029/232] - Fix wrong size calculation for PSymbolTable::MarkSymbols(). SVN r2259 (scripting) --- src/dobjtype.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 1649ca46a..4e0cdf9ea 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -490,7 +490,7 @@ size_t PSymbolTable::MarkSymbols() GC::Mark(pair->Value); count++; } - return count * sizeof(Symbols[0]); + return count * sizeof(PSymbol*); } void PSymbolTable::ReleaseSymbols() From ef3c020c8cdd5a00e977ca9a5f1b80cb8f224e62 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 31 Mar 2010 02:44:22 +0000 Subject: [PATCH 030/232] - Actually, I think this is proper now. SVN r2260 (scripting) --- src/dobjtype.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 4e0cdf9ea..d2ec92d15 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -490,7 +490,7 @@ size_t PSymbolTable::MarkSymbols() GC::Mark(pair->Value); count++; } - return count * sizeof(PSymbol*); + return count * sizeof(*pair); } void PSymbolTable::ReleaseSymbols() From 549ddf80359ae14cf80c690c930b362fa045c5cd Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 3 Apr 2010 02:06:51 +0000 Subject: [PATCH 031/232] - Use the standard DObject type system for the PSymbol hierarchy. SVN r2264 (scripting) --- src/d_dehacked.cpp | 43 +++++++++++++--------------- src/dobject.cpp | 35 +++++++++------------- src/dobjtype.h | 27 ++++++----------- src/p_acs.cpp | 12 +++----- src/thingdef/thingdef.cpp | 6 ++++ src/thingdef/thingdef_codeptr.cpp | 14 +++------ src/thingdef/thingdef_data.cpp | 6 +--- src/thingdef/thingdef_expression.cpp | 12 ++++---- src/thingdef/thingdef_states.cpp | 5 ++-- 9 files changed, 65 insertions(+), 95 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 5a9e10145..24b4c0b78 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -82,7 +82,7 @@ static void UnloadDehSupp (); // This is a list of all the action functions used by each of Doom's states. -static TArray<PSymbol *> Actions; +static TArray<PSymbolActionFunction *> Actions; // These are the original heights of every Doom 2 thing. They are used if a patch // specifies that a thing should be hanging from the ceiling but doesn't specify @@ -156,7 +156,7 @@ static TArray<MBFParamState> MBFParamStates; // Data on how to correctly modify the codepointers struct CodePointerAlias { - char name[20]; + FName name; char alias[20]; BYTE params; }; @@ -630,11 +630,9 @@ void SetDehParams(FState * state, int codepointer) FScriptPosition * pos = new FScriptPosition(FString("DEHACKED"), 0); // Let's identify the codepointer we're dealing with. - PSymbolActionFunction * sym; PSymbol * s; - s = RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(FName(MBFCodePointers[codepointer].name), true); - if (!s || s->SymbolType != SYM_ActionFunction) return; - sym = static_cast<PSymbolActionFunction*>(s); - + PSymbolActionFunction *sym; + sym = dyn_cast<PSymbolActionFunction>(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(FName(MBFCodePointers[codepointer].name), true)); + if (sym == NULL) return; // Bleargh! This will all have to be redone once scripting works @@ -1598,22 +1596,20 @@ static int PatchWeapon (int weapNum) return result; } -static void SetPointer(FState *state, PSymbol *sym, int frame = 0) +static void SetPointer(FState *state, PSymbolActionFunction *sym, int frame = 0) { - if (sym==NULL || sym->SymbolType != SYM_ActionFunction) + if (sym == NULL) { state->SetAction(NULL); return; } else { - FString symname = sym->SymbolName.GetChars(); - state->SetAction(static_cast<PSymbolActionFunction*>(sym)->Function); + state->SetAction(sym->Function); - // Note: CompareNoCase() calls stricmp() and therefore returns 0 when they're the same. for (unsigned int i = 0; i < MBFCodePointers.Size(); i++) { - if (!symname.CompareNoCase(MBFCodePointers[i].name)) + if (sym->SymbolName == MBFCodePointers[i].name) { MBFParamState newstate; newstate.state = state; @@ -1667,7 +1663,9 @@ static int PatchPointer (int ptrNum) { int index = atoi(Line2); if ((unsigned)(index) >= Actions.Size()) + { SetPointer(state, NULL); + } else { SetPointer(state, Actions[index], CodePConv[ptrNum]); @@ -1990,15 +1988,15 @@ static int PatchCodePtrs (int dummy) // This skips the action table and goes directly to the internal symbol table // DEH compatible functions are easy to recognize. - PSymbol *sym = RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(symname, true); - if (sym == NULL || sym->SymbolType != SYM_ActionFunction) + PSymbolActionFunction *sym = dyn_cast<PSymbolActionFunction>(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(symname, true)); + if (sym == NULL) { Printf("Frame %d: Unknown code pointer '%s'\n", frame, Line2); } else { - FString &args = static_cast<PSymbolActionFunction*>(sym)->Arguments; - if (args.Len()!=0 && (args[0]<'a' || args[0]>'z')) + FString &args = sym->Arguments; + if (args.Len() != 0 && (args[0] < 'a' || args[0] > 'z')) { Printf("Frame %d: Incompatible code pointer '%s'\n", frame, Line2); sym = NULL; @@ -2579,15 +2577,15 @@ static bool LoadDehSupp () // or AActor so this will find all of them. FString name = "A_"; name << sc.String; - PSymbol *sym = RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(name, true); - if (sym == NULL || sym->SymbolType != SYM_ActionFunction) + PSymbolActionFunction *sym = dyn_cast<PSymbolActionFunction>(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(name, true)); + if (sym == NULL) { sc.ScriptError("Unknown code pointer '%s'", sc.String); } else { - FString &args = static_cast<PSymbolActionFunction*>(sym)->Arguments; - if (args.Len()!=0 && (args[0]<'a' || args[0]>'z')) + FString &args = sym->Arguments; + if (args.Len() != 0 && (args[0] < 'a' || args[0] > 'z')) { sc.ScriptError("Incompatible code pointer '%s'", sc.String); } @@ -2814,8 +2812,7 @@ static bool LoadDehSupp () temp.alias[19]=0; sc.MustGetStringName(","); sc.MustGetString(); - strncpy(temp.name, sc.String, 19); - temp.name[19]=0; + temp.name = sc.String; sc.MustGetStringName(","); sc.MustGetNumber(); temp.params = sc.Number; diff --git a/src/dobject.cpp b/src/dobject.cpp index 405c96514..959b25d58 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -394,21 +394,17 @@ void DObject::SerializeUserVars(FArchive &arc) while (it.NextPair(pair)) { - PSymbol *sym = pair->Value; - if (sym->SymbolType == SYM_Variable) + PSymbolVariable *var = dyn_cast<PSymbolVariable>(pair->Value); + if (var != NULL && var->bUserVar) { - PSymbolVariable *var = static_cast<PSymbolVariable *>(sym); - if (var->bUserVar) - { - count = var->ValueType.Type == VAL_Array ? var->ValueType.size : 1; - varloc = (int *)(reinterpret_cast<BYTE *>(this) + var->offset); + count = var->ValueType.Type == VAL_Array ? var->ValueType.size : 1; + varloc = (int *)(reinterpret_cast<BYTE *>(this) + var->offset); - arc << var->SymbolName; - arc.WriteCount(count); - for (j = 0; j < count; ++j) - { - arc << varloc[j]; - } + arc << var->SymbolName; + arc.WriteCount(count); + for (j = 0; j < count; ++j) + { + arc << varloc[j]; } } } @@ -423,18 +419,13 @@ void DObject::SerializeUserVars(FArchive &arc) arc << varname; while (varname != NAME_None) { - PSymbol *sym = symt->FindSymbol(varname, true); + PSymbolVariable *var = dyn_cast<PSymbolVariable>(symt->FindSymbol(varname, true)); DWORD wanted = 0; - if (sym != NULL && sym->SymbolType == SYM_Variable) + if (var != NULL && var->bUserVar) { - PSymbolVariable *var = static_cast<PSymbolVariable *>(sym); - - if (var->bUserVar) - { - wanted = var->ValueType.Type == VAL_Array ? var->ValueType.size : 1; - varloc = (int *)(reinterpret_cast<BYTE *>(this) + var->offset); - } + wanted = var->ValueType.Type == VAL_Array ? var->ValueType.size : 1; + varloc = (int *)(reinterpret_cast<BYTE *>(this) + var->offset); } count = arc.ReadCount(); for (j = 0; j < MIN(wanted, count); ++j) diff --git a/src/dobjtype.h b/src/dobjtype.h index 1090d659e..ac8e64e7e 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -10,25 +10,16 @@ // Symbol information ------------------------------------------------------- -enum ESymbolType -{ - SYM_Const, - SYM_Variable, - SYM_ActionFunction, - SYM_VMFunction -}; - class PSymbol : public DObject { DECLARE_ABSTRACT_CLASS(PSymbol, DObject); public: virtual ~PSymbol(); - ESymbolType SymbolType; FName SymbolName; protected: - PSymbol(FName name, ESymbolType type) { SymbolType = type; SymbolName = name; } + PSymbol(FName name) { SymbolName = name; } }; // A constant value --------------------------------------------------------- @@ -44,8 +35,8 @@ public: double Float; }; - PSymbolConst(FName name) : PSymbol(name, SYM_Const) {} - PSymbolConst() : PSymbol(NAME_None, SYM_Const) {} + PSymbolConst(FName name) : PSymbol(name) {} + PSymbolConst() : PSymbol(NAME_None) {} }; // A variable --------------------------------------------------------- @@ -59,8 +50,8 @@ public: intptr_t offset; bool bUserVar; - PSymbolVariable(FName name) : PSymbol(name, SYM_Variable) {} - PSymbolVariable() : PSymbol(NAME_None, SYM_Variable) {} + PSymbolVariable(FName name) : PSymbol(name) {} + PSymbolVariable() : PSymbol(NAME_None) {} }; // An action function ------------------------------------------------------- @@ -98,8 +89,8 @@ public: VMFunction *Function; int defaultparameterindex; - PSymbolActionFunction(FName name) : PSymbol(name, SYM_ActionFunction) {} - PSymbolActionFunction() : PSymbol(NAME_None, SYM_ActionFunction) {} + PSymbolActionFunction(FName name) : PSymbol(name) {} + PSymbolActionFunction() : PSymbol(NAME_None) {} }; // A VM function ------------------------------------------------------------ @@ -111,8 +102,8 @@ class PSymbolVMFunction : public PSymbol public: VMFunction *Function; - PSymbolVMFunction(FName name) : PSymbol(name, SYM_VMFunction) {} - PSymbolVMFunction() : PSymbol(NAME_None, SYM_VMFunction) {} + PSymbolVMFunction(FName name) : PSymbol(name) {} + PSymbolVMFunction() : PSymbol(NAME_None) {} }; // A symbol table ----------------------------------------------------------- diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 576709a9d..32b28db3e 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -2976,12 +2976,10 @@ int DLevelScript::LineFromID(int id) static void SetUserVariable(AActor *self, FName varname, int index, int value) { - PSymbol *sym = self->GetClass()->Symbols.FindSymbol(varname, true); int max; - PSymbolVariable *var; + PSymbolVariable *var = dyn_cast<PSymbolVariable>(self->GetClass()->Symbols.FindSymbol(varname, true)); - if (sym == NULL || sym->SymbolType != SYM_Variable || - !(var = static_cast<PSymbolVariable *>(sym))->bUserVar) + if (var == NULL || !var->bUserVar) { return; } @@ -3006,12 +3004,10 @@ static void SetUserVariable(AActor *self, FName varname, int index, int value) static int GetUserVariable(AActor *self, FName varname, int index) { - PSymbol *sym = self->GetClass()->Symbols.FindSymbol(varname, true); int max; - PSymbolVariable *var; + PSymbolVariable *var = dyn_cast<PSymbolVariable>(self->GetClass()->Symbols.FindSymbol(varname, true)); - if (sym == NULL || sym->SymbolType != SYM_Variable || - !(var = static_cast<PSymbolVariable *>(sym))->bUserVar) + if (var == NULL || !var->bUserVar) { return 0; } diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 3d4106050..4cc1b9bf7 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -65,6 +65,7 @@ #include "thingdef_exp.h" #include "a_sharedglobal.h" #include "vmbuilder.h" +#include "stats.h" // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- void InitThingdef(); @@ -368,7 +369,9 @@ static void FinishThingdef() void LoadActors () { int lastlump, lump; + cycle_t timer; + timer.Reset(); timer.Clock(); FScriptPosition::ResetErrorCounter(); InitThingdef(); lastlump = 0; @@ -382,5 +385,8 @@ void LoadActors () I_Error("%d errors while parsing DECORATE scripts", FScriptPosition::ErrorCounter); } FinishThingdef(); + timer.Unclock(); + Printf("DECORATE parsing took %.2f ms\n", timer.TimeMS()); + // Base time: ~52 ms } diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index c501daf04..72bfb4d1f 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -3132,12 +3132,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserVar) PARAM_NAME (varname); PARAM_INT (value); - PSymbol *sym = self->GetClass()->Symbols.FindSymbol(varname, true); - PSymbolVariable *var; + PSymbolVariable *var = dyn_cast<PSymbolVariable>(self->GetClass()->Symbols.FindSymbol(varname, true)); - if (sym == NULL || sym->SymbolType != SYM_Variable || - !(var = static_cast<PSymbolVariable *>(sym))->bUserVar || - var->ValueType.Type != VAL_Int) + if (var == NULL || !var->bUserVar || var->ValueType.Type != VAL_Int) { Printf("%s is not a user variable in class %s\n", varname.GetChars(), self->GetClass()->TypeName.GetChars()); @@ -3161,12 +3158,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserArray) PARAM_INT (pos); PARAM_INT (value); - PSymbol *sym = self->GetClass()->Symbols.FindSymbol(varname, true); - PSymbolVariable *var; + PSymbolVariable *var = dyn_cast<PSymbolVariable>(self->GetClass()->Symbols.FindSymbol(varname, true)); - if (sym == NULL || sym->SymbolType != SYM_Variable || - !(var = static_cast<PSymbolVariable *>(sym))->bUserVar || - var->ValueType.Type != VAL_Array || var->ValueType.BaseType != VAL_Int) + if (var == NULL || !var->bUserVar || var->ValueType.Type != VAL_Array || var->ValueType.BaseType != VAL_Int) { Printf("%s is not a user array in class %s\n", varname.GetChars(), self->GetClass()->TypeName.GetChars()); diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 45777f061..1d7018907 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -525,11 +525,7 @@ FVariableInfo *FindVariable(const char * string, const PClass *cls) PSymbolActionFunction *FindGlobalActionFunction(const char *name) { - PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol(name, false); - if (sym != NULL && sym->SymbolType == SYM_ActionFunction) - return static_cast<PSymbolActionFunction*>(sym); - else - return NULL; + return dyn_cast<PSymbolActionFunction>(RUNTIME_CLASS(AActor)->Symbols.FindSymbol(name, false)); } diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 78a115c34..9ff623a5e 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -453,9 +453,9 @@ ExpVal FxConstant::EvalExpression (AActor *self) FxExpression *FxConstant::MakeConstant(PSymbol *sym, const FScriptPosition &pos) { FxExpression *x; - if (sym->SymbolType == SYM_Const) + PSymbolConst *csym = dyn_cast<PSymbolConst>(sym); + if (csym != NULL) { - PSymbolConst *csym = static_cast<PSymbolConst*>(sym); switch(csym->ValueType) { case VAL_Int: @@ -2728,12 +2728,12 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) // see if the current class (if valid) defines something with this name. if ((sym = ctx.FindInClass(Identifier)) != NULL) { - if (sym->SymbolType == SYM_Const) + if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) { ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as class constant\n", Identifier.GetChars()); newex = FxConstant::MakeConstant(sym, ScriptPosition); } - else if (sym->SymbolType == SYM_Variable) + else if (sym->IsKindOf(RUNTIME_CLASS(PSymbolVariable))) { PSymbolVariable *vsym = static_cast<PSymbolVariable*>(sym); ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as member variable, index %d\n", Identifier.GetChars(), vsym->offset); @@ -2747,12 +2747,12 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) // now check the global identifiers. else if ((sym = ctx.FindGlobal(Identifier)) != NULL) { - if (sym->SymbolType == SYM_Const) + if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) { ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as global constant\n", Identifier.GetChars()); newex = FxConstant::MakeConstant(sym, ScriptPosition); } - else if (sym->SymbolType == SYM_Variable) // global variables will always be native + else if (sym->IsKindOf(RUNTIME_CLASS(PSymbolVariable))) // global variables will always be native { PSymbolVariable *vsym = static_cast<PSymbolVariable*>(sym); ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as global variable, address %d\n", Identifier.GetChars(), vsym->offset); diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index 6aeec63f8..095e19661 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -272,10 +272,9 @@ do_stop: goto endofstate; } - PSymbol *sym = bag.Info->Symbols.FindSymbol (FName(sc.String, true), true); - if (sym != NULL && sym->SymbolType == SYM_ActionFunction) + PSymbolActionFunction *afd = dyn_cast<PSymbolActionFunction>(bag.Info->Symbols.FindSymbol (FName(sc.String, true), true)); + if (afd != NULL) { - PSymbolActionFunction *afd = static_cast<PSymbolActionFunction *>(sym); tcall->Function = afd->Function; if (!afd->Arguments.IsEmpty()) { From 06995e26d9d6a2184a7d16187ffda4b9d7b76b70 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 3 Apr 2010 04:07:17 +0000 Subject: [PATCH 032/232] - Be stricter about types accepted by spawning functions. SVN r2265 (scripting) --- src/actor.h | 18 ++++++------------ src/d_dehacked.cpp | 6 +++--- src/d_dehacked.h | 2 +- src/d_player.h | 4 ++-- src/farchive.cpp | 20 ++++++++++---------- src/farchive.h | 24 ++++++++++++------------ src/g_doom/a_arachnotron.cpp | 2 +- src/g_doom/a_bossbrain.cpp | 6 +++--- src/g_doom/a_bruiser.cpp | 2 +- src/g_doom/a_cacodemon.cpp | 2 +- src/g_doom/a_cyberdemon.cpp | 2 +- src/g_doom/a_doomimp.cpp | 2 +- src/g_doom/a_fatso.cpp | 2 -- src/g_doom/a_painelemental.cpp | 16 ++++++++-------- src/g_doom/a_revenant.cpp | 2 +- src/g_doom/a_scriptedmarine.cpp | 6 +++--- src/g_game.cpp | 2 +- src/g_heretic/a_ironlich.cpp | 4 ++-- src/g_heretic/a_knight.cpp | 4 ++-- src/g_hexen/a_bishop.cpp | 2 +- src/g_hexen/a_blastradius.cpp | 2 +- src/g_hexen/a_clericholy.cpp | 2 +- src/g_hexen/a_dragon.cpp | 4 ++-- src/g_hexen/a_fighterquietus.cpp | 2 +- src/g_hexen/a_firedemon.cpp | 14 +++++++------- src/g_hexen/a_flechette.cpp | 2 +- src/g_hexen/a_healingradius.cpp | 4 ++-- src/g_hexen/a_hexenspecialdecs.cpp | 2 +- src/g_hexen/a_iceguy.cpp | 4 ++-- src/g_hexen/a_korax.cpp | 12 ++++++------ src/g_raven/a_minotaur.cpp | 8 ++++---- src/g_shared/a_action.cpp | 7 +++++-- src/g_shared/a_artifacts.cpp | 4 ++-- src/g_shared/a_debris.cpp | 4 ++-- src/g_shared/a_fastprojectile.cpp | 2 +- src/g_shared/a_morph.cpp | 14 +++++++------- src/g_shared/a_morph.h | 6 +++--- src/g_shared/a_pickups.cpp | 2 +- src/g_shared/a_randomspawner.cpp | 20 +++++++++++++++----- src/g_shared/a_sharedglobal.h | 2 +- src/g_strife/a_alienspectres.cpp | 4 +--- src/g_strife/a_entityboss.cpp | 2 +- src/g_strife/a_spectral.cpp | 8 +++----- src/g_strife/a_strifeitems.cpp | 2 +- src/g_strife/a_strifestuff.cpp | 2 +- src/g_strife/a_strifeweapons.cpp | 8 +++----- src/info.h | 4 ++-- src/m_cheat.cpp | 21 +++++++++++---------- src/p_acs.cpp | 16 ++++++++-------- src/p_enemy.cpp | 14 ++++++++------ src/p_enemy.h | 2 +- src/p_lnspec.cpp | 2 +- src/p_local.h | 10 +++++++--- src/p_mobj.cpp | 12 ++++++------ src/p_states.cpp | 8 ++++---- src/p_teleport.cpp | 2 +- src/p_terrain.h | 6 +++--- src/p_user.cpp | 2 +- src/thingdef/thingdef_codeptr.cpp | 8 ++++---- 59 files changed, 192 insertions(+), 186 deletions(-) diff --git a/src/actor.h b/src/actor.h index 1dcf22c9b..d1d7f4a0f 100644 --- a/src/actor.h +++ b/src/actor.h @@ -40,6 +40,8 @@ #include "r_blend.h" #include "s_sound.h" +class PClassAmmo; + // // NOTES: AActor // @@ -625,13 +627,13 @@ public: } // Adds one item of a particular type. Returns NULL if it could not be added. - AInventory *GiveInventoryType (const PClass *type); + AInventory *GiveInventoryType (PClassActor *type); // Returns the first item held with IF_INVBAR set. AInventory *FirstInv (); // Tries to give the actor some ammo. - bool GiveAmmo (const PClass *type, int amount); + bool GiveAmmo (PClassAmmo *type, int amount); // Destroys all the inventory the actor is holding. void DestroyAllInventory (); @@ -948,18 +950,10 @@ public: } }; -inline AActor *Spawn (PClass *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement) +inline AActor *Spawn (PClassActor *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement) { - return AActor::StaticSpawn (dyn_cast<PClassActor>(type), x, y, z, allowreplacement); + return AActor::StaticSpawn (type, x, y, z, allowreplacement); } - -inline AActor *Spawn (const PClass *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement) -{ - // Thanks to some fiddling while determining replacements, type is modified, but only - // temporarily. - return AActor::StaticSpawn (const_cast<PClassActor *>(dyn_cast<PClassActor>(type)), x, y, z, allowreplacement); -} - AActor *Spawn (const char *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement); AActor *Spawn (FName classname, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement); diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 24b4c0b78..9d7c54f7a 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -2896,7 +2896,7 @@ void ModifyDropAmount(AInventory *inv, int dropamount); bool ADehackedPickup::TryPickup (AActor *&toucher) { - const PClass *type = DetermineType (); + PClassActor *type = DetermineType (); if (type == NULL) { return false; @@ -2968,7 +2968,7 @@ void ADehackedPickup::Destroy () Super::Destroy (); } -const PClass *ADehackedPickup::DetermineType () +PClassActor *ADehackedPickup::DetermineType () { // Look at the actor's current sprite to determine what kind of // item to pretend to me. @@ -2981,7 +2981,7 @@ const PClass *ADehackedPickup::DetermineType () int lex = memcmp (DehSpriteMappings[mid].Sprite, sprites[sprite].name, 4); if (lex == 0) { - return PClass::FindClass (DehSpriteMappings[mid].ClassName); + return PClass::FindActor(DehSpriteMappings[mid].ClassName); } else if (lex < 0) { diff --git a/src/d_dehacked.h b/src/d_dehacked.h index 67473f071..71716bdcf 100644 --- a/src/d_dehacked.h +++ b/src/d_dehacked.h @@ -50,7 +50,7 @@ public: void DoPickupSpecial (AActor *toucher); void Serialize(FArchive &arc); private: - const PClass *DetermineType (); + PClassActor *DetermineType (); AInventory *RealPickup; public: bool droppedbymonster; diff --git a/src/d_player.h b/src/d_player.h index 75f0fbfa1..9f9942c86 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -250,7 +250,7 @@ public: userinfo_t userinfo; // [RH] who is this? - const PClass *cls; // class of associated PlayerPawn + PClassPlayerPawn *cls; // class of associated PlayerPawn float DesiredFOV; // desired field of vision float FOV; // current field of vision @@ -302,7 +302,7 @@ public: int morphTics; // player is a chicken/pig if > 0 BYTE MorphedPlayerClass; // [MH] (for SBARINFO) class # for this player instance when morphed int MorphStyle; // which effects to apply for this player instance when morphed - const PClass *MorphExitFlash; // flash to apply when demorphing (cache of value given to P_MorphPlayer) + PClassActor *MorphExitFlash; // flash to apply when demorphing (cache of value given to P_MorphPlayer) TObjPtr<AWeapon> PremorphWeapon; // ready weapon before morphing int chickenPeck; // chicken peck countdown int jumpTics; // delay the next jump for a moment diff --git a/src/farchive.cpp b/src/farchive.cpp index 6b9ba2790..f2aff5a45 100644 --- a/src/farchive.cpp +++ b/src/farchive.cpp @@ -1043,7 +1043,7 @@ FArchive &FArchive::WriteObject (DObject *obj) } else { - const PClass *type = RUNTIME_TYPE(obj); + PClass *type = RUNTIME_TYPE(obj); if (type == RUNTIME_CLASS(DObject)) { @@ -1361,7 +1361,7 @@ DWORD FArchive::FindName (const char *name, unsigned int bucket) const return (DWORD)map; } -DWORD FArchive::WriteClass (const PClass *info) +DWORD FArchive::WriteClass (PClass *info) { if (m_ClassCount >= PClass::m_Types.Size()) { @@ -1378,7 +1378,7 @@ DWORD FArchive::WriteClass (const PClass *info) return m_ClassCount++; } -const PClass *FArchive::ReadClass () +PClass *FArchive::ReadClass () { struct String { String() { val = NULL; } @@ -1410,9 +1410,9 @@ const PClass *FArchive::ReadClass () return NULL; } -const PClass *FArchive::ReadClass (const PClass *wanttype) +PClass *FArchive::ReadClass (const PClass *wanttype) { - const PClass *type = ReadClass (); + PClass *type = ReadClass (); if (!type->IsDescendantOf (wanttype)) { I_Error ("Expected to extract an object of type '%s'.\n" @@ -1422,14 +1422,14 @@ const PClass *FArchive::ReadClass (const PClass *wanttype) return type; } -const PClass *FArchive::ReadStoredClass (const PClass *wanttype) +PClass *FArchive::ReadStoredClass (const PClass *wanttype) { DWORD index = ReadCount (); if (index >= m_ClassCount) { I_Error ("Class reference too high (%u; max is %u)\n", index, m_ClassCount); } - const PClass *type = m_TypeMap[index].toCurrent; + PClass *type = m_TypeMap[index].toCurrent; if (!type->IsDescendantOf (wanttype)) { I_Error ("Expected to extract an object of type '%s'.\n" @@ -1479,7 +1479,7 @@ DWORD FArchive::FindObjectIndex (const DObject *obj) const return index; } -void FArchive::UserWriteClass (const PClass *type) +void FArchive::UserWriteClass (PClass *type) { BYTE id; @@ -1505,7 +1505,7 @@ void FArchive::UserWriteClass (const PClass *type) } } -void FArchive::UserReadClass (const PClass *&type) +void FArchive::UserReadClass (PClass *&type) { BYTE newclass; @@ -1527,7 +1527,7 @@ void FArchive::UserReadClass (const PClass *&type) } } -FArchive &operator<< (FArchive &arc, const PClass * &info) +FArchive &operator<< (FArchive &arc, PClass *&info) { if (arc.IsStoring ()) { diff --git a/src/farchive.h b/src/farchive.h index 31a0358e8..e994e6d56 100644 --- a/src/farchive.h +++ b/src/farchive.h @@ -167,13 +167,13 @@ virtual void Read (void *mem, unsigned int len); void WriteCount (DWORD count); DWORD ReadCount (); - void UserWriteClass (const PClass *info); - void UserReadClass (const PClass *&info); - template<typename T> void UserReadClass(const T *&info) + void UserWriteClass (PClass *info); + void UserReadClass (PClass *&info); + template<typename T> void UserReadClass(T *&info) { - const PClass *myclass; + PClass *myclass; UserReadClass(myclass); - info = dyn_cast<T>(const_cast<PClass *>(myclass)); + info = dyn_cast<T>(myclass); } FArchive& operator<< (BYTE &c); @@ -211,10 +211,10 @@ protected: DWORD FindObjectIndex (const DObject *obj) const; DWORD MapObject (const DObject *obj); - DWORD WriteClass (const PClass *info); - const PClass *ReadClass (); - const PClass *ReadClass (const PClass *wanttype); - const PClass *ReadStoredClass (const PClass *wanttype); + DWORD WriteClass (PClass *info); + PClass *ReadClass (); + PClass *ReadClass (const PClass *wanttype); + PClass *ReadStoredClass (const PClass *wanttype); DWORD HashObject (const DObject *obj) const; DWORD AddName (const char *name); DWORD AddName (unsigned int start); // Name has already been added to storage @@ -232,8 +232,8 @@ protected: struct TypeMap { - const PClass *toCurrent; // maps archive type index to execution type index - DWORD toArchive; // maps execution type index to archive type index + PClass *toCurrent; // maps archive type index to execution type index + DWORD toArchive; // maps execution type index to archive type index enum { NO_INDEX = 0xffffffff }; } *m_TypeMap; @@ -287,7 +287,7 @@ inline FArchive &operator<< (FArchive &arc, T* &object) return arc.SerializeObject ((DObject*&)object, RUNTIME_CLASS(T)); } -FArchive &operator<< (FArchive &arc, const PClass * &info); +FArchive &operator<< (FArchive &arc, PClass * &info); class FFont; FArchive &SerializeFFontPtr (FArchive &arc, FFont* &font); diff --git a/src/g_doom/a_arachnotron.cpp b/src/g_doom/a_arachnotron.cpp index 65e258720..0f42431c3 100644 --- a/src/g_doom/a_arachnotron.cpp +++ b/src/g_doom/a_arachnotron.cpp @@ -17,7 +17,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BspiAttack) A_FaceTarget (self); // launch a missile - P_SpawnMissile (self, self->target, PClass::FindClass("ArachnotronPlasma")); + P_SpawnMissile (self, self->target, PClass::FindActor("ArachnotronPlasma")); return 0; } diff --git a/src/g_doom/a_bossbrain.cpp b/src/g_doom/a_bossbrain.cpp index a91d5f0e9..ef8d23b8f 100644 --- a/src/g_doom/a_bossbrain.cpp +++ b/src/g_doom/a_bossbrain.cpp @@ -152,7 +152,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BrainSpit) return 0; } -static void SpawnFly(AActor *self, const PClass *spawntype, FSoundID sound) +static void SpawnFly(AActor *self, PClassActor *spawntype, FSoundID sound) { AActor *newmobj; AActor *fog; @@ -242,7 +242,7 @@ static void SpawnFly(AActor *self, const PClass *spawntype, FSoundID sound) else if (r < 246) SpawnName = "HellKnight"; else SpawnName = "BaronOfHell"; } - spawntype = PClass::FindClass(SpawnName); + spawntype = PClass::FindActor(SpawnName); if (spawntype != NULL) { newmobj = Spawn (spawntype, targ->x, targ->y, targ->z, ALLOW_REPLACE); @@ -293,6 +293,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnSound) { PARAM_ACTION_PROLOGUE; S_Sound (self, CHAN_BODY, "brain/cube", 1, ATTN_IDLE); - SpawnFly(self, PClass::FindClass("SpawnFire"), "brain/spawn"); + SpawnFly(self, PClass::FindActor("SpawnFire"), "brain/spawn"); return 0; } diff --git a/src/g_doom/a_bruiser.cpp b/src/g_doom/a_bruiser.cpp index c4adec04f..97dc64775 100644 --- a/src/g_doom/a_bruiser.cpp +++ b/src/g_doom/a_bruiser.cpp @@ -18,6 +18,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_BruisAttack) } // launch a missile - P_SpawnMissile (self, self->target, PClass::FindClass("BaronBall")); + P_SpawnMissile (self, self->target, PClass::FindActor("BaronBall")); return 0; } diff --git a/src/g_doom/a_cacodemon.cpp b/src/g_doom/a_cacodemon.cpp index 1fd9b3ce4..d405ea425 100644 --- a/src/g_doom/a_cacodemon.cpp +++ b/src/g_doom/a_cacodemon.cpp @@ -30,6 +30,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_HeadAttack) } // launch a missile - P_SpawnMissile (self, self->target, PClass::FindClass("CacodemonBall")); + P_SpawnMissile (self, self->target, PClass::FindActor("CacodemonBall")); return 0; } diff --git a/src/g_doom/a_cyberdemon.cpp b/src/g_doom/a_cyberdemon.cpp index a7d7409ea..5b436f2f3 100644 --- a/src/g_doom/a_cyberdemon.cpp +++ b/src/g_doom/a_cyberdemon.cpp @@ -15,7 +15,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CyberAttack) return 0; A_FaceTarget (self); - P_SpawnMissile (self, self->target, PClass::FindClass("Rocket")); + P_SpawnMissile (self, self->target, PClass::FindActor("Rocket")); return 0; } diff --git a/src/g_doom/a_doomimp.cpp b/src/g_doom/a_doomimp.cpp index 025fb7d27..681d1c79d 100644 --- a/src/g_doom/a_doomimp.cpp +++ b/src/g_doom/a_doomimp.cpp @@ -33,6 +33,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_TroopAttack) } // launch a missile - P_SpawnMissile (self, self->target, PClass::FindClass("DoomImpBall")); + P_SpawnMissile (self, self->target, PClass::FindActor("DoomImpBall")); return 0; } diff --git a/src/g_doom/a_fatso.cpp b/src/g_doom/a_fatso.cpp index 2d55b49c7..46aa076ab 100644 --- a/src/g_doom/a_fatso.cpp +++ b/src/g_doom/a_fatso.cpp @@ -124,8 +124,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FatAttack3) // Original idea: Linguica // -AActor * P_OldSpawnMissile(AActor * source, AActor * owner, AActor * dest, const PClass *type); - enum { MSF_Standard = 0, diff --git a/src/g_doom/a_painelemental.cpp b/src/g_doom/a_painelemental.cpp index b8be64f59..142c23a92 100644 --- a/src/g_doom/a_painelemental.cpp +++ b/src/g_doom/a_painelemental.cpp @@ -12,9 +12,9 @@ DECLARE_ACTION(A_SkullAttack) -static const PClass *GetSpawnType(VMValue *param) +static PClassActor *GetSpawnType(VMValue *param) { - const PClass *spawntype; + PClassActor *spawntype; if (param == NULL || param->Type == REGT_NIL) { @@ -24,10 +24,10 @@ static const PClass *GetSpawnType(VMValue *param) { assert(param->Type == REGT_POINTER); assert(param->atag == ATAG_OBJECT || param->a == NULL); - spawntype = (const PClass *)param->a; + spawntype = (PClassActor *)param->a; } - return (spawntype != NULL) ? spawntype : PClass::FindClass("LostSoul"); + return (spawntype != NULL) ? spawntype : PClass::FindActor("LostSoul"); } @@ -35,7 +35,7 @@ static const PClass *GetSpawnType(VMValue *param) // A_PainShootSkull // Spawn a lost soul and launch it at the target // -void A_PainShootSkull (AActor *self, angle_t angle, const PClass *spawntype) +void A_PainShootSkull (AActor *self, angle_t angle, PClassActor *spawntype) { fixed_t x, y, z; @@ -150,7 +150,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PainAttack) if (!self->target) return 0; - const PClass *spawntype = GetSpawnType(numparam > NAP ? ¶m[NAP] : NULL); + PClassActor *spawntype = GetSpawnType(numparam > NAP ? ¶m[NAP] : NULL); A_FaceTarget (self); A_PainShootSkull (self, self->angle, spawntype); return 0; @@ -163,7 +163,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DualPainAttack) if (!self->target) return 0; - const PClass *spawntype = GetSpawnType(numparam > NAP ? ¶m[NAP] : NULL); + PClassActor *spawntype = GetSpawnType(numparam > NAP ? ¶m[NAP] : NULL); A_FaceTarget (self); A_PainShootSkull (self, self->angle + ANG45, spawntype); A_PainShootSkull (self, self->angle - ANG45, spawntype); @@ -178,7 +178,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PainDie) { // And I thought you were my friend! self->flags &= ~MF_FRIENDLY; } - const PClass *spawntype = GetSpawnType(numparam > NAP ? ¶m[NAP] : NULL); + PClassActor *spawntype = GetSpawnType(numparam > NAP ? ¶m[NAP] : NULL); CALL_ACTION(A_NoBlocking, self); A_PainShootSkull (self, self->angle + ANG90, spawntype); A_PainShootSkull (self, self->angle + ANG180, spawntype); diff --git a/src/g_doom/a_revenant.cpp b/src/g_doom/a_revenant.cpp index 4d78f359f..59aa83fe2 100644 --- a/src/g_doom/a_revenant.cpp +++ b/src/g_doom/a_revenant.cpp @@ -29,7 +29,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkelMissile) A_FaceTarget (self); missile = P_SpawnMissileZ (self, self->z + 48*FRACUNIT, - self->target, PClass::FindClass("RevenantTracer")); + self->target, PClass::FindActor("RevenantTracer")); if (missile != NULL) { diff --git a/src/g_doom/a_scriptedmarine.cpp b/src/g_doom/a_scriptedmarine.cpp index ffaae7eec..4260bbcd5 100644 --- a/src/g_doom/a_scriptedmarine.cpp +++ b/src/g_doom/a_scriptedmarine.cpp @@ -523,7 +523,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_FireMissile) else { A_FaceTarget (self); - P_SpawnMissile (self, self->target, PClass::FindClass("Rocket")); + P_SpawnMissile (self, self->target, PClass::FindActor("Rocket")); } return 0; } @@ -560,7 +560,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_FirePlasma) return 0; A_FaceTarget (self); - P_SpawnMissile (self, self->target, PClass::FindClass("PlasmaBall")); + P_SpawnMissile (self, self->target, PClass::FindActor("PlasmaBall")); self->special1 = level.maptime + 20; return 0; } @@ -606,7 +606,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_FireBFG) return 0; A_FaceTarget (self); - P_SpawnMissile (self, self->target, PClass::FindClass("BFGBall")); + P_SpawnMissile (self, self->target, PClass::FindActor("BFGBall")); self->special1 = level.maptime + 30; self->PainChance = MARINE_PAIN_CHANCE; return 0; diff --git a/src/g_game.cpp b/src/g_game.cpp index 77554bb26..52f07ad9c 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1283,7 +1283,7 @@ void G_PlayerReborn (int player) userinfo_t userinfo; // [RH] Save userinfo botskill_t b_skill;//Added by MC: APlayerPawn *actor; - const PClass *cls; + PClassPlayerPawn *cls; FString log; p = &players[player]; diff --git a/src/g_heretic/a_ironlich.cpp b/src/g_heretic/a_ironlich.cpp index f21dc5208..7b30e77e3 100644 --- a/src/g_heretic/a_ironlich.cpp +++ b/src/g_heretic/a_ironlich.cpp @@ -94,12 +94,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack) randAttack = pr_atk (); if (randAttack < atkResolve1[dist]) { // Ice ball - P_SpawnMissile (self, target, PClass::FindClass("HeadFX1")); + P_SpawnMissile (self, target, PClass::FindActor("HeadFX1")); S_Sound (self, CHAN_BODY, "ironlich/attack2", 1, ATTN_NORM); } else if (randAttack < atkResolve2[dist]) { // Fire column - baseFire = P_SpawnMissile (self, target, PClass::FindClass("HeadFX3")); + baseFire = P_SpawnMissile (self, target, PClass::FindActor("HeadFX3")); if (baseFire != NULL) { baseFire->SetState (baseFire->FindState("NoGrow")); diff --git a/src/g_heretic/a_knight.cpp b/src/g_heretic/a_knight.cpp index d6a3d2760..36e83488b 100644 --- a/src/g_heretic/a_knight.cpp +++ b/src/g_heretic/a_knight.cpp @@ -61,11 +61,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_KnightAttack) S_Sound (self, CHAN_BODY, self->AttackSound, 1, ATTN_NORM); if (self->flags & MF_SHADOW || pr_knightatk () < 40) { // Red axe - P_SpawnMissileZ (self, self->z + 36*FRACUNIT, self->target, PClass::FindClass("RedAxe")); + P_SpawnMissileZ (self, self->z + 36*FRACUNIT, self->target, PClass::FindActor("RedAxe")); return 0; } // Green axe - P_SpawnMissileZ (self, self->z + 36*FRACUNIT, self->target, PClass::FindClass("KnightAxe")); + P_SpawnMissileZ (self, self->z + 36*FRACUNIT, self->target, PClass::FindActor("KnightAxe")); return 0; } diff --git a/src/g_hexen/a_bishop.cpp b/src/g_hexen/a_bishop.cpp index 23b4de431..e1d6e1d76 100644 --- a/src/g_hexen/a_bishop.cpp +++ b/src/g_hexen/a_bishop.cpp @@ -61,7 +61,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopAttack2) self->SetState (self->SeeState); return 0; } - mo = P_SpawnMissile (self, self->target, PClass::FindClass("BishopFX")); + mo = P_SpawnMissile (self, self->target, PClass::FindActor("BishopFX")); if (mo != NULL) { mo->tracer = self->target; diff --git a/src/g_hexen/a_blastradius.cpp b/src/g_hexen/a_blastradius.cpp index 3ab01f4a5..d08dd6673 100644 --- a/src/g_hexen/a_blastradius.cpp +++ b/src/g_hexen/a_blastradius.cpp @@ -22,7 +22,7 @@ // //========================================================================== -void BlastActor (AActor *victim, fixed_t strength, fixed_t speed, AActor * Owner, const PClass * blasteffect) +void BlastActor (AActor *victim, fixed_t strength, fixed_t speed, AActor *Owner, PClassActor *blasteffect) { angle_t angle,ang; AActor *mo; diff --git a/src/g_hexen/a_clericholy.cpp b/src/g_hexen/a_clericholy.cpp index d9171dc8b..a38b99e12 100644 --- a/src/g_hexen/a_clericholy.cpp +++ b/src/g_hexen/a_clericholy.cpp @@ -574,7 +574,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ClericAttack) if (!self->target) return 0; - AActor * missile = P_SpawnMissileZ (self, self->z + 40*FRACUNIT, self->target, PClass::FindClass ("HolyMissile")); + AActor * missile = P_SpawnMissileZ (self, self->z + 40*FRACUNIT, self->target, PClass::FindActor("HolyMissile")); if (missile != NULL) missile->tracer = NULL; // No initial target S_Sound (self, CHAN_WEAPON, "HolySymbolFire", 1, ATTN_NORM); return 0; diff --git a/src/g_hexen/a_dragon.cpp b/src/g_hexen/a_dragon.cpp index 87f58f196..7b0467dc8 100644 --- a/src/g_hexen/a_dragon.cpp +++ b/src/g_hexen/a_dragon.cpp @@ -93,7 +93,7 @@ static void DragonSeek (AActor *actor, angle_t thresh, angle_t turnMax) } else if (pr_dragonseek() < 128 && P_CheckMissileRange(actor)) { - P_SpawnMissile(actor, target, PClass::FindClass ("DragonFireball")); + P_SpawnMissile(actor, target, PClass::FindActor("DragonFireball")); S_Sound (actor, CHAN_WEAPON, actor->AttackSound, 1, ATTN_NORM); } actor->target = oldTarget; @@ -255,7 +255,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonAttack) { PARAM_ACTION_PROLOGUE; - P_SpawnMissile (self, self->target, PClass::FindClass ("DragonFireball")); + P_SpawnMissile (self, self->target, PClass::FindActor("DragonFireball")); return 0; } diff --git a/src/g_hexen/a_fighterquietus.cpp b/src/g_hexen/a_fighterquietus.cpp index 6a73b7eca..3b6b7542c 100644 --- a/src/g_hexen/a_fighterquietus.cpp +++ b/src/g_hexen/a_fighterquietus.cpp @@ -70,7 +70,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DropWeaponPieces) for (int i = 0, j = 0, fineang = 0; i < 3; ++i) { - const PClass *cls = j==0? p1 : j==1? p2 : p3; + PClassActor *cls = j == 0 ? p1 : j == 1 ? p2 : p3; if (cls) { AActor *piece = Spawn (cls, self->x, self->y, self->z, ALLOW_REPLACE); diff --git a/src/g_hexen/a_firedemon.cpp b/src/g_hexen/a_firedemon.cpp index d13b6600e..ae93715e3 100644 --- a/src/g_hexen/a_firedemon.cpp +++ b/src/g_hexen/a_firedemon.cpp @@ -33,25 +33,25 @@ void A_FiredSpawnRock (AActor *actor) { AActor *mo; int x,y,z; - const PClass *rtype; + PClassActor *rtype; switch (pr_firedemonrock() % 5) { case 0: - rtype = PClass::FindClass ("FireDemonRock1"); + rtype = PClass::FindActor("FireDemonRock1"); break; case 1: - rtype = PClass::FindClass ("FireDemonRock2"); + rtype = PClass::FindActor("FireDemonRock2"); break; case 2: - rtype = PClass::FindClass ("FireDemonRock3"); + rtype = PClass::FindActor("FireDemonRock3"); break; case 3: - rtype = PClass::FindClass ("FireDemonRock4"); + rtype = PClass::FindActor("FireDemonRock4"); break; case 4: default: - rtype = PClass::FindClass ("FireDemonRock5"); + rtype = PClass::FindActor("FireDemonRock5"); break; } @@ -121,7 +121,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredAttack) if (self->target == NULL) return 0; - AActor *mo = P_SpawnMissile (self, self->target, PClass::FindClass ("FireDemonMissile")); + AActor *mo = P_SpawnMissile (self, self->target, PClass::FindActor("FireDemonMissile")); if (mo) S_Sound (self, CHAN_BODY, "FireDemonAttack", 1, ATTN_NORM); return 0; } diff --git a/src/g_hexen/a_flechette.cpp b/src/g_hexen/a_flechette.cpp index 7e60ec0a3..092203050 100644 --- a/src/g_hexen/a_flechette.cpp +++ b/src/g_hexen/a_flechette.cpp @@ -204,7 +204,7 @@ AInventory *AArtiPoisonBag::CreateCopy (AActor *other) } AInventory *copy; - const PClass *spawntype; + PClassActor *spawntype; if (other->IsKindOf (PClass::FindClass(NAME_ClericPlayer))) { diff --git a/src/g_hexen/a_healingradius.cpp b/src/g_hexen/a_healingradius.cpp index a18116dac..a4e66eb10 100644 --- a/src/g_hexen/a_healingradius.cpp +++ b/src/g_hexen/a_healingradius.cpp @@ -70,8 +70,8 @@ bool AArtiHealingRadius::Use (bool pickup) { int amount = 50 + (pr_healradius() % 50); - if (players[i].mo->GiveAmmo (PClass::FindClass(NAME_Mana1), amount) || - players[i].mo->GiveAmmo (PClass::FindClass(NAME_Mana2), amount)) + if (players[i].mo->GiveAmmo (dyn_cast<PClassAmmo>(PClass::FindClass(NAME_Mana1)), amount) || + players[i].mo->GiveAmmo (dyn_cast<PClassAmmo>(PClass::FindClass(NAME_Mana2)), amount)) { gotsome = true; } diff --git a/src/g_hexen/a_hexenspecialdecs.cpp b/src/g_hexen/a_hexenspecialdecs.cpp index 4f513cfe0..9012c3885 100644 --- a/src/g_hexen/a_hexenspecialdecs.cpp +++ b/src/g_hexen/a_hexenspecialdecs.cpp @@ -214,7 +214,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LeafSpawn) for (i = (pr_leaf()&3)+1; i; i--) { - mo = Spawn (pr_leaf()&1 ? PClass::FindClass ("Leaf1") : PClass::FindClass ("Leaf2"), + mo = Spawn (pr_leaf()&1 ? PClass::FindActor("Leaf1") : PClass::FindActor("Leaf2"), self->x + (pr_leaf.Random2()<<14), self->y + (pr_leaf.Random2()<<14), self->z + (pr_leaf()<<14), ALLOW_REPLACE); diff --git a/src/g_hexen/a_iceguy.cpp b/src/g_hexen/a_iceguy.cpp index e4a501443..c5f43ba30 100644 --- a/src/g_hexen/a_iceguy.cpp +++ b/src/g_hexen/a_iceguy.cpp @@ -100,12 +100,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceGuyAttack) P_SpawnMissileXYZ(self->x+FixedMul(self->radius>>1, finecosine[an]), self->y+FixedMul(self->radius>>1, finesine[an]), self->z+40*FRACUNIT, self, self->target, - PClass::FindClass ("IceGuyFX")); + PClass::FindActor("IceGuyFX")); an = (self->angle-ANG90)>>ANGLETOFINESHIFT; P_SpawnMissileXYZ(self->x+FixedMul(self->radius>>1, finecosine[an]), self->y+FixedMul(self->radius>>1, finesine[an]), self->z+40*FRACUNIT, self, self->target, - PClass::FindClass ("IceGuyFX")); + PClass::FindActor("IceGuyFX")); S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); return 0; } diff --git a/src/g_hexen/a_korax.cpp b/src/g_hexen/a_korax.cpp index d0509c408..74f346fb6 100644 --- a/src/g_hexen/a_korax.cpp +++ b/src/g_hexen/a_korax.cpp @@ -74,10 +74,10 @@ void A_KSpiritRoam (AActor *); void A_KBolt (AActor *); void A_KBoltRaise (AActor *); -void KoraxFire (AActor *actor, const PClass *type, int arm); +void KoraxFire (AActor *actor, PClassActor *type, int arm); void KSpiritInit (AActor *spirit, AActor *korax); AActor *P_SpawnKoraxMissile (fixed_t x, fixed_t y, fixed_t z, - AActor *source, AActor *dest, const PClass *type); + AActor *source, AActor *dest, PClassActor *type); extern void SpawnSpiritTail (AActor *spirit); @@ -237,11 +237,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxMissile) int type = pr_koraxmissile()%6; int i; - const PClass *info; + PClassActor *info; S_Sound (self, CHAN_VOICE, "KoraxAttack", 1, ATTN_NORM); - info = PClass::FindClass (choices[type].type); + info = PClass::FindActor(choices[type].type); if (info == NULL) { I_Error ("Unknown Korax missile: %s\n", choices[type].type); @@ -310,7 +310,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxCommand) // //============================================================================ -void KoraxFire (AActor *actor, const PClass *type, int arm) +void KoraxFire (AActor *actor, PClassActor *type, int arm) { static const int extension[6] = { @@ -533,7 +533,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KBoltRaise) //============================================================================ AActor *P_SpawnKoraxMissile (fixed_t x, fixed_t y, fixed_t z, - AActor *source, AActor *dest, const PClass *type) + AActor *source, AActor *dest, PClassActor *type) { AActor *th; angle_t an; diff --git a/src/g_raven/a_minotaur.cpp b/src/g_raven/a_minotaur.cpp index 138ef59f6..f2bd43ebc 100644 --- a/src/g_raven/a_minotaur.cpp +++ b/src/g_raven/a_minotaur.cpp @@ -246,15 +246,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurCharge) } if (self->special1 > 0) { - const PClass *type; + PClassActor *type; if (gameinfo.gametype == GAME_Heretic) { - type = PClass::FindClass ("PhoenixPuff"); + type = PClass::FindActor("PhoenixPuff"); } else { - type = PClass::FindClass ("PunchPuff"); + type = PClass::FindActor("PunchPuff"); } puff = Spawn (type, self->x, self->y, self->z, ALLOW_REPLACE); puff->velz = 2*FRACUNIT; @@ -362,7 +362,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk3) } else { - mo = P_SpawnMissile (self, self->target, PClass::FindClass("MinotaurFX2")); + mo = P_SpawnMissile (self, self->target, PClass::FindActor("MinotaurFX2")); if (mo != NULL) { S_Sound (mo, CHAN_WEAPON, "minotaur/attack1", 1, ATTN_NORM); diff --git a/src/g_shared/a_action.cpp b/src/g_shared/a_action.cpp index abaaa4e3e..6261591d9 100644 --- a/src/g_shared/a_action.cpp +++ b/src/g_shared/a_action.cpp @@ -91,8 +91,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_NoBlocking) { if (di->Name != NAME_None) { - const PClass *ti = PClass::FindClass(di->Name); - if (ti) P_DropItem (self, ti, di->Amount, di->Probability); + PClassActor *ti = PClass::FindActor(di->Name); + if (ti != NULL) + { + P_DropItem (self, ti, di->Amount, di->Probability); + } } di = di->Next; } diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index 0dcfac57c..48cd26370 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -1727,8 +1727,8 @@ void APowerMorph::InitEffect( ) if (Owner != NULL && Owner->player != NULL && PlayerClass != NAME_None) { player_t *realplayer = Owner->player; // Remember the identity of the player - const PClass *morph_flash = PClass::FindClass (MorphFlash); - const PClass *unmorph_flash = PClass::FindClass (UnMorphFlash); + PClassActor *morph_flash = PClass::FindActor(MorphFlash); + PClassActor *unmorph_flash = PClass::FindActor(UnMorphFlash); PClassPlayerPawn *player_class = dyn_cast<PClassPlayerPawn>(PClass::FindClass (PlayerClass)); if (P_MorphPlayer(realplayer, realplayer, player_class, -1/*INDEFINITELY*/, MorphStyle, morph_flash, unmorph_flash)) { diff --git a/src/g_shared/a_debris.cpp b/src/g_shared/a_debris.cpp index e6fc79b0a..807f8e3ef 100644 --- a/src/g_shared/a_debris.cpp +++ b/src/g_shared/a_debris.cpp @@ -32,7 +32,7 @@ IMPLEMENT_CLASS(AGlassShard) void P_SpawnDirt (AActor *actor, fixed_t radius) { fixed_t x,y,z; - const PClass *dtype = NULL; + PClassActor *dtype = NULL; AActor *mo; angle_t angle; @@ -43,7 +43,7 @@ void P_SpawnDirt (AActor *actor, fixed_t radius) char fmt[8]; mysnprintf(fmt, countof(fmt), "Dirt%d", 1 + pr_dirt()%6); - dtype = PClass::FindClass(fmt); + dtype = PClass::FindActor(fmt); if (dtype) { mo = Spawn (dtype, x, y, z, ALLOW_REPLACE); diff --git a/src/g_shared/a_fastprojectile.cpp b/src/g_shared/a_fastprojectile.cpp index 614985234..e319ca1b3 100644 --- a/src/g_shared/a_fastprojectile.cpp +++ b/src/g_shared/a_fastprojectile.cpp @@ -163,7 +163,7 @@ void AFastProjectile::Effect() hitz = floorz; } - const PClass *trail = PClass::FindClass(name); + PClassActor *trail = PClass::FindActor(name); if (trail != NULL) { AActor *act = Spawn (trail, x, y, hitz, ALLOW_REPLACE); diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 70f79b3a0..0cdd48768 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -25,7 +25,7 @@ static FRandom pr_morphmonst ("MorphMonster"); // //--------------------------------------------------------------------------- -bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntype, int duration, int style, const PClass *enter_flash, const PClass *exit_flash) +bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntype, int duration, int style, PClassActor *enter_flash, PClassActor *exit_flash) { AInventory *item; APlayerPawn *morphed; @@ -246,7 +246,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, mo->flags2 = (mo->flags2 & ~MF2_FLY) | (pmo->flags2 & MF2_FLY); mo->flags3 = (mo->flags3 & ~MF3_GHOST) | (pmo->flags3 & MF3_GHOST); - const PClass *exit_flash = player->MorphExitFlash; + PClassActor *exit_flash = player->MorphExitFlash; bool correctweapon = !!(player->MorphStyle & MORPH_LOSEACTUALWEAPON); bool undobydeathsaves = !!(player->MorphStyle & MORPH_UNDOBYDEATHSAVES); @@ -372,7 +372,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, // //--------------------------------------------------------------------------- -bool P_MorphMonster (AActor *actor, const PClass *spawntype, int duration, int style, const PClass *enter_flash, const PClass *exit_flash) +bool P_MorphMonster (AActor *actor, PClassActor *spawntype, int duration, int style, PClassActor *enter_flash, PClassActor *exit_flash) { AMorphedMonster *morphed; @@ -464,7 +464,7 @@ bool P_UndoMonsterMorph (AMorphedMonster *beast, bool force) actor->AddToHash (); beast->UnmorphedMe = NULL; DObject::StaticPointerSubstitution (beast, actor); - const PClass *exit_flash = beast->MorphExitFlash; + PClassActor *exit_flash = beast->MorphExitFlash; beast->Destroy (); Spawn(exit_flash, beast->x, beast->y, beast->z + TELEFOGHEIGHT, ALLOW_REPLACE); return true; @@ -552,8 +552,8 @@ IMPLEMENT_CLASS(AMorphProjectile) int AMorphProjectile::DoSpecialDamage (AActor *target, int damage) { - const PClass *morph_flash = PClass::FindClass (MorphFlash); - const PClass *unmorph_flash = PClass::FindClass (UnMorphFlash); + PClassActor *morph_flash = PClass::FindActor(MorphFlash); + PClassActor *unmorph_flash = PClass::FindActor(UnMorphFlash); if (target->player) { PClassPlayerPawn *player_class = dyn_cast<PClassPlayerPawn>(PClass::FindClass(PlayerClass)); @@ -561,7 +561,7 @@ int AMorphProjectile::DoSpecialDamage (AActor *target, int damage) } else { - const PClass *monster_class = PClass::FindClass (MonsterClass); + PClassActor *monster_class = PClass::FindActor(MonsterClass); P_MorphMonster (target, monster_class, Duration, MorphStyle, morph_flash, unmorph_flash); } return -1; diff --git a/src/g_shared/a_morph.h b/src/g_shared/a_morph.h index 8ea90bf5d..fb0e4c65d 100644 --- a/src/g_shared/a_morph.h +++ b/src/g_shared/a_morph.h @@ -34,10 +34,10 @@ class player_t; class AMorphedMonster; bool P_MorphPlayer (player_t *activator, player_t *player, PClassPlayerPawn *morphclass, int duration = 0, int style = 0, - const PClass *enter_flash = NULL, const PClass *exit_flash = NULL); + PClassActor *enter_flash = NULL, PClassActor *exit_flash = NULL); bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag = 0, bool force = false); -bool P_MorphMonster (AActor *actor, const PClass *morphclass, int duration = 0, int style = 0, - const PClass *enter_flash = NULL, const PClass *exit_flash = NULL); +bool P_MorphMonster (AActor *actor, PClassActor *morphclass, int duration = 0, int style = 0, + PClassActor *enter_flash = NULL, PClassActor *exit_flash = NULL); bool P_UndoMonsterMorph (AMorphedMonster *beast, bool force = false); bool P_UpdateMorphedMonster (AActor *actor); bool P_MorphedDeath(AActor *actor, AActor **morphed, int *morphedstyle, int *morphedhealth); diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 8d895bb68..f877de77b 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -1660,7 +1660,7 @@ AInventory *ABackpackItem::CreateCopy (AActor *other) if (amount < 0) amount = 0; if (ammo == NULL) { // The player did not have the ammo. Add it. - ammo = static_cast<AAmmo *>(Spawn (type, 0, 0, 0, NO_REPLACE)); + ammo = static_cast<AAmmo *>(Spawn(atype, 0, 0, 0, NO_REPLACE)); ammo->Amount = bDepleted ? 0 : amount; if (ammo->BackpackMaxAmount > ammo->MaxAmount) { diff --git a/src/g_shared/a_randomspawner.cpp b/src/g_shared/a_randomspawner.cpp index 48e21e791..60c8372f9 100644 --- a/src/g_shared/a_randomspawner.cpp +++ b/src/g_shared/a_randomspawner.cpp @@ -100,16 +100,26 @@ class ARandomSpawner : public AActor // necessary to them -- such as their source and destination. void PostBeginPlay() { - AActor * newmobj = NULL; + AActor *newmobj = NULL; bool boss = false; - if (Species == NAME_None) { Destroy(); return; } - const PClass * cls = PClass::FindClass(Species); + if (Species == NAME_None) + { + Destroy(); + return; + } + PClassActor *cls = PClass::FindActor(Species); if (this->flags & MF_MISSILE && target && target->target) // Attempting to spawn a missile. { - if ((tracer == NULL) && (flags2 & MF2_SEEKERMISSILE)) tracer = target->target; + if ((tracer == NULL) && (flags2 & MF2_SEEKERMISSILE)) + { + tracer = target->target; + } newmobj = P_SpawnMissileXYZ(x, y, z, target, target->target, cls, false); } - else newmobj = Spawn(cls, x, y, z, NO_REPLACE); + else + { + newmobj = Spawn(cls, x, y, z, NO_REPLACE); + } if (newmobj != NULL) { // copy everything relevant diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h index c152bf44d..46073253f 100644 --- a/src/g_shared/a_sharedglobal.h +++ b/src/g_shared/a_sharedglobal.h @@ -176,7 +176,7 @@ public: TObjPtr<AActor> UnmorphedMe; int UnmorphTime, MorphStyle; - const PClass *MorphExitFlash; + PClassActor *MorphExitFlash; DWORD FlagsSave; }; diff --git a/src/g_strife/a_alienspectres.cpp b/src/g_strife/a_alienspectres.cpp index 1c58805b9..0e79642ad 100644 --- a/src/g_strife/a_alienspectres.cpp +++ b/src/g_strife/a_alienspectres.cpp @@ -16,8 +16,6 @@ static FRandom pr_spectrespawn ("AlienSpectreSpawn"); static FRandom pr_spectrechunk ("212e4"); -AActor *P_SpawnSubMissile (AActor *source, const PClass *type, AActor *target); - //============================================================================ DEFINE_ACTION_FUNCTION(AActor, A_SpectreChunkSmall) @@ -80,7 +78,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Spectre3Attack) for (int i = 0; i < 20; ++i) { self->angle += ANGLE_180 / 20; - P_SpawnSubMissile (self, PClass::FindClass("SpectralLightningBall2"), self); + P_SpawnSubMissile (self, PClass::FindActor("SpectralLightningBall2"), self); } self->angle -= ANGLE_180 / 20 * 10; return 0; diff --git a/src/g_strife/a_entityboss.cpp b/src/g_strife/a_entityboss.cpp index 3df9a786a..d9b4db285 100644 --- a/src/g_strife/a_entityboss.cpp +++ b/src/g_strife/a_entityboss.cpp @@ -28,7 +28,7 @@ void A_SpectralMissile (AActor *self, const char *missilename) if (self->target != NULL) { AActor *missile = P_SpawnMissileXYZ (self->x, self->y, self->z + 32*FRACUNIT, - self, self->target, PClass::FindClass(missilename), false); + self, self->target, PClass::FindActor(missilename), false); if (missile != NULL) { missile->tracer = self->target; diff --git a/src/g_strife/a_spectral.cpp b/src/g_strife/a_spectral.cpp index 75757500a..5e1ea9a63 100644 --- a/src/g_strife/a_spectral.cpp +++ b/src/g_strife/a_spectral.cpp @@ -9,8 +9,6 @@ #include "thingdef/thingdef.h" */ -AActor *P_SpawnSubMissile (AActor *source, const PClass *type, AActor *target); - class ASpectralMonster : public AActor { DECLARE_CLASS (ASpectralMonster, AActor) @@ -41,7 +39,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpectralBigBallLightning) { PARAM_ACTION_PROLOGUE; - const PClass *cls = PClass::FindClass("SpectralLightningH3"); + PClassActor *cls = PClass::FindActor("SpectralLightningH3"); if (cls) { self->angle += ANGLE_90; @@ -72,8 +70,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpectralLightning) x = self->x + pr_zap5.Random2(3) * FRACUNIT * 50; y = self->y + pr_zap5.Random2(3) * FRACUNIT * 50; - flash = Spawn (self->threshold > 25 ? PClass::FindClass(NAME_SpectralLightningV2) : - PClass::FindClass(NAME_SpectralLightningV1), x, y, ONCEILINGZ, ALLOW_REPLACE); + flash = Spawn (self->threshold > 25 ? PClass::FindActor(NAME_SpectralLightningV2) : + PClass::FindActor(NAME_SpectralLightningV1), x, y, ONCEILINGZ, ALLOW_REPLACE); flash->target = self->target; flash->velz = -18*FRACUNIT; diff --git a/src/g_strife/a_strifeitems.cpp b/src/g_strife/a_strifeitems.cpp index e5cc4136e..38aa2e758 100644 --- a/src/g_strife/a_strifeitems.cpp +++ b/src/g_strife/a_strifeitems.cpp @@ -81,7 +81,7 @@ bool AHealthTraining::TryPickup (AActor *&toucher) { if (Super::TryPickup (toucher)) { - toucher->GiveInventoryType (PClass::FindClass("GunTraining")); + toucher->GiveInventoryType (PClass::FindActor("GunTraining")); AInventory *coin = Spawn<ACoin> (0,0,0, NO_REPLACE); if (coin != NULL) { diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index d747872a8..822e5c596 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -566,7 +566,7 @@ void APowerCoupling::Die (AActor *source, AActor *inflictor) players[i].mo->GiveInventoryType (QuestItemClasses[5]); S_Sound (CHAN_VOICE, "svox/voc13", 1, ATTN_NORM); players[i].SetLogNumber (13); - P_DropItem (this, PClass::FindClass("BrokenPowerCoupling"), -1, 256); + P_DropItem (this, PClass::FindActor("BrokenPowerCoupling"), -1, 256); Destroy (); } diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp index 4e3db52ae..da345f692 100644 --- a/src/g_strife/a_strifeweapons.cpp +++ b/src/g_strife/a_strifeweapons.cpp @@ -522,8 +522,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMauler2) // //============================================================================ -AActor *P_SpawnSubMissile (AActor *source, const PClass *type, AActor *target); - DEFINE_ACTION_FUNCTION(AActor, A_MaulerTorpedoWave) { PARAM_ACTION_PROLOGUE; @@ -542,13 +540,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_MaulerTorpedoWave) for (int i = 0; i < 80; ++i) { self->angle += ANGLE_45/10; - P_SpawnSubMissile (self, PClass::FindClass("MaulerTorpedoWave"), self->target); + P_SpawnSubMissile (self, PClass::FindActor("MaulerTorpedoWave"), self->target); } self->z = savedz; return 0; } -AActor *P_SpawnSubMissile (AActor *source, const PClass *type, AActor *target) +AActor *P_SpawnSubMissile (AActor *source, PClassActor *type, AActor *target) { AActor *other = Spawn (type, source->x, source->y, source->z, ALLOW_REPLACE); @@ -1040,7 +1038,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil3) for (i = 0; i < 20; ++i) { self->angle += ANGLE_180/20; - spot = P_SpawnSubMissile (self, PClass::FindClass("SpectralLightningBall1"), self); + spot = P_SpawnSubMissile (self, PClass::FindActor("SpectralLightningBall1"), self); if (spot != NULL) { spot->z = self->z + 32*FRACUNIT; diff --git a/src/info.h b/src/info.h index bf7a38fbc..3af996b44 100644 --- a/src/info.h +++ b/src/info.h @@ -95,8 +95,8 @@ struct FState } void SetAction(VMFunction *func) { ActionFunc = func; } bool CallAction(AActor *self, AActor *stateowner, StateCallData *statecall = NULL); - static const PClassActor *StaticFindStateOwner (const FState *state); - static const PClassActor *StaticFindStateOwner (const FState *state, const PClassActor *info); + static PClassActor *StaticFindStateOwner (const FState *state); + static PClassActor *StaticFindStateOwner (const FState *state, PClassActor *info); }; struct FStateLabels; diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index ad948264e..bb59780bd 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -250,7 +250,7 @@ void cht_DoCheat (player_t *player, int cheat) { if (i != 0) { - player->mo->GiveInventoryType (*BeholdPowers[i]); + player->mo->GiveInventoryType(static_cast<PClassActor *>(*BeholdPowers[i])); if (cheat == CHT_BEHOLDS) { P_GiveBody (player->mo, -100); @@ -551,7 +551,7 @@ const char *cht_Morph (player_t *player, PClassPlayerPawn *morphclass, bool quic return ""; } -void GiveSpawner (player_t *player, const PClass *type, int amount) +void GiveSpawner (player_t *player, PClassInventory *type, int amount) { if (player->mo == NULL || player->health <= 0) { @@ -648,7 +648,7 @@ void cht_Give (player_t *player, const char *name, int amount) type = PClass::FindClass(gameinfo.backpacktype); if (type != NULL) { - GiveSpawner (player, type, 1); + GiveSpawner (player, static_cast<PClassInventory *>(type), 1); } if (!giveall) @@ -665,10 +665,11 @@ void cht_Give (player_t *player, const char *name, int amount) if (type->ParentClass == RUNTIME_CLASS(AAmmo)) { - AInventory *ammo = player->mo->FindInventory(static_cast<PClassActor *>(type)); + PClassAmmo *atype = static_cast<PClassAmmo *>(type); + AInventory *ammo = player->mo->FindInventory(atype); if (ammo == NULL) { - ammo = static_cast<AInventory *>(Spawn (type, 0, 0, 0, NO_REPLACE)); + ammo = static_cast<AInventory *>(Spawn (atype, 0, 0, 0, NO_REPLACE)); ammo->AttachToOwner (player->mo); ammo->Amount = ammo->MaxAmount; } @@ -722,7 +723,7 @@ void cht_Give (player_t *player, const char *name, int amount) AKey *key = (AKey *)GetDefaultByType (PClass::m_Types[i]); if (key->KeyNumber != 0) { - key = static_cast<AKey *>(Spawn (PClass::m_Types[i], 0,0,0, NO_REPLACE)); + key = static_cast<AKey *>(Spawn(static_cast<PClassActor *>(PClass::m_Types[i]), 0,0,0, NO_REPLACE)); if (!key->CallTryPickup (player->mo)) { key->Destroy (); @@ -755,7 +756,7 @@ void cht_Give (player_t *player, const char *name, int amount) AWeapon *def = (AWeapon*)GetDefaultByType (type); if (!(def->WeaponFlags & WIF_CHEATNOTWEAPON)) { - GiveSpawner (player, type, 1); + GiveSpawner (player, static_cast<PClassInventory *>(type), 1); } } } @@ -779,7 +780,7 @@ void cht_Give (player_t *player, const char *name, int amount) !type->IsDescendantOf (RUNTIME_CLASS(APowerup)) && !type->IsDescendantOf (RUNTIME_CLASS(AArmor))) { - GiveSpawner (player, type, 1); + GiveSpawner (player, static_cast<PClassInventory *>(type), 1); } } } @@ -797,7 +798,7 @@ void cht_Give (player_t *player, const char *name, int amount) AInventory *def = (AInventory*)GetDefaultByType (type); if (def->Icon.isValid()) { - GiveSpawner (player, type, 1); + GiveSpawner (player, static_cast<PClassInventory *>(type), 1); } } } @@ -816,7 +817,7 @@ void cht_Give (player_t *player, const char *name, int amount) } else { - GiveSpawner (player, type, amount); + GiveSpawner (player, static_cast<PClassInventory *>(type), amount); } return; } diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 32b28db3e..202eb24ab 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -424,7 +424,7 @@ static void ClearInventory (AActor *activator) // //============================================================================ -static void DoGiveInv (AActor *actor, const PClass *info, int amount) +static void DoGiveInv (AActor *actor, PClassActor *info, int amount) { AWeapon *savedPendingWeap = actor->player != NULL ? actor->player->PendingWeapon : NULL; @@ -479,7 +479,7 @@ static void DoGiveInv (AActor *actor, const PClass *info, int amount) static void GiveInventory (AActor *activator, const char *type, int amount) { - const PClass *info; + PClassActor *info; if (amount <= 0 || type == NULL) { @@ -489,7 +489,7 @@ static void GiveInventory (AActor *activator, const char *type, int amount) { type = "BasicArmorPickup"; } - info = PClass::FindClass (type); + info = PClass::FindActor(type); if (info == NULL) { Printf ("ACS: I don't know what %s is.\n", type); @@ -2259,7 +2259,7 @@ void DLevelScript::ReplaceTextures (int fromnamei, int tonamei, int flags) int DLevelScript::DoSpawn (int type, fixed_t x, fixed_t y, fixed_t z, int tid, int angle, bool force) { - const PClass *info = PClass::FindClass (FBehavior::StaticLookupString (type)); + PClassActor *info = PClass::FindActor(FBehavior::StaticLookupString (type)); AActor *actor = NULL; int spawncount = 0; @@ -5536,7 +5536,7 @@ int DLevelScript::RunScript () } else { - item = activator->GiveInventoryType (type); + item = activator->GiveInventoryType (static_cast<PClassAmmo *>(type)); item->MaxAmount = STACK(1); item->Amount = 0; } @@ -6356,13 +6356,13 @@ int DLevelScript::RunScript () FName playerclass_name = FBehavior::StaticLookupString(STACK(6)); PClassPlayerPawn *playerclass = dyn_cast<PClassPlayerPawn>(PClass::FindClass (playerclass_name)); FName monsterclass_name = FBehavior::StaticLookupString(STACK(5)); - const PClass *monsterclass = PClass::FindClass (monsterclass_name); + PClassActor *monsterclass = PClass::FindActor(monsterclass_name); int duration = STACK(4); int style = STACK(3); FName morphflash_name = FBehavior::StaticLookupString(STACK(2)); - const PClass *morphflash = PClass::FindClass (morphflash_name); + PClassActor *morphflash = PClass::FindActor(morphflash_name); FName unmorphflash_name = FBehavior::StaticLookupString(STACK(1)); - const PClass *unmorphflash = PClass::FindClass (unmorphflash_name); + PClassActor *unmorphflash = PClass::FindActor(unmorphflash_name); int changes = 0; if (tag == 0) diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index c08e9ff7f..69146fd99 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -2907,7 +2907,7 @@ void ModifyDropAmount(AInventory *inv, int dropamount) CVAR(Int, sv_dropstyle, 0, CVAR_SERVERINFO | CVAR_ARCHIVE); -AInventory *P_DropItem (AActor *source, const PClass *type, int dropamount, int chance) +AInventory *P_DropItem (AActor *source, PClassActor *type, int dropamount, int chance) { if (type != NULL && pr_dropitem() <= chance) { @@ -2918,9 +2918,11 @@ AInventory *P_DropItem (AActor *source, const PClass *type, int dropamount, int if (!(i_compatflags & COMPATF_NOTOSSDROPS)) { int style = sv_dropstyle; - if (style==0) style= (gameinfo.gametype == GAME_Strife)? 2:1; - - if (style==2) + if (style == 0) + { + style = (gameinfo.gametype == GAME_Strife) ? 2 : 1; + } + if (style == 2) { spawnz += 24*FRACUNIT; } @@ -2929,7 +2931,7 @@ AInventory *P_DropItem (AActor *source, const PClass *type, int dropamount, int spawnz += source->height / 2; } } - mo = Spawn (type, source->x, source->y, spawnz, ALLOW_REPLACE); + mo = Spawn(type, source->x, source->y, spawnz, ALLOW_REPLACE); if (mo != NULL) { mo->flags |= MF_DROPPED; @@ -2940,7 +2942,7 @@ AInventory *P_DropItem (AActor *source, const PClass *type, int dropamount, int } if (mo->IsKindOf (RUNTIME_CLASS(AInventory))) { - AInventory * inv = static_cast<AInventory *>(mo); + AInventory *inv = static_cast<AInventory *>(mo); ModifyDropAmount(inv, dropamount); if (inv->SpecialDropAction (source)) { diff --git a/src/p_enemy.h b/src/p_enemy.h index 4b66f9d20..9c1aee156 100644 --- a/src/p_enemy.h +++ b/src/p_enemy.h @@ -51,7 +51,7 @@ bool P_CheckMeleeRange2 (AActor *actor); bool P_Move (AActor *actor); bool P_TryWalk (AActor *actor); void P_NewChaseDir (AActor *actor); -AInventory *P_DropItem (AActor *source, const PClass *type, int special, int chance); +AInventory *P_DropItem (AActor *source, PClassActor *type, int special, int chance); void P_TossItem (AActor *item); bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params); void A_Weave(AActor *self, int xyspeed, int zspeed, fixed_t xydist, fixed_t zdist); diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 4dda3cc24..82fa2efa7 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -2556,7 +2556,7 @@ FUNC(LS_SetPlayerProperty) { // Give power to activator if (power != 4) { - APowerup *item = static_cast<APowerup*>(it->GiveInventoryType (*powers[power])); + APowerup *item = static_cast<APowerup*>(it->GiveInventoryType(static_cast<PClassActor *>(*powers[power]))); if (item != NULL && power == 0 && arg1 == 1) { item->BlendColor = MakeSpecialColormap(INVERSECOLORMAP); diff --git a/src/p_local.h b/src/p_local.h index 822d6f787..4139f314e 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -111,9 +111,10 @@ void P_RipperBlood (AActor *mo, AActor *bleeder); int P_GetThingFloorType (AActor *thing); void P_ExplodeMissile (AActor *missile, line_t *explodeline, AActor *target); -AActor *P_SpawnMissile (AActor* source, AActor* dest, const PClass *type, AActor* owner = NULL); -AActor *P_SpawnMissileZ (AActor* source, fixed_t z, AActor* dest, const PClass *type); -AActor *P_SpawnMissileXYZ (fixed_t x, fixed_t y, fixed_t z, AActor *source, AActor *dest, const PClass *type, bool checkspawn = true, AActor *owner = NULL); +AActor * P_OldSpawnMissile(AActor *source, AActor *owner, AActor *dest, PClassActor *type); +AActor *P_SpawnMissile (AActor* source, AActor* dest, PClassActor *type, AActor* owner = NULL); +AActor *P_SpawnMissileZ (AActor* source, fixed_t z, AActor* dest, PClassActor *type); +AActor *P_SpawnMissileXYZ (fixed_t x, fixed_t y, fixed_t z, AActor *source, AActor *dest, PClassActor *type, bool checkspawn = true, AActor *owner = NULL); AActor *P_SpawnMissileAngle (AActor *source, PClassActor *type, angle_t angle, fixed_t velz); AActor *P_SpawnMissileAngleSpeed (AActor *source, PClassActor *type, angle_t angle, fixed_t velz, fixed_t speed); AActor *P_SpawnMissileAngleZ (AActor *source, fixed_t z, PClassActor *type, angle_t angle, fixed_t velz); @@ -127,6 +128,9 @@ AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, P void P_CheckFakeFloorTriggers (AActor *mo, fixed_t oldz, bool oldz_has_viewheight=false); +AActor *P_SpawnSubMissile (AActor *source, PClassActor *type, AActor *target); // Strife uses it + + // // [RH] P_THINGS // diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index caed7d7b9..4b38cb93a 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -849,7 +849,7 @@ AInventory *AActor::FindInventory (FName type) // //============================================================================ -AInventory *AActor::GiveInventoryType (const PClass *type) +AInventory *AActor::GiveInventoryType (PClassActor *type) { AInventory *item = NULL; @@ -873,7 +873,7 @@ AInventory *AActor::GiveInventoryType (const PClass *type) // //============================================================================ -bool AActor::GiveAmmo (const PClass *type, int amount) +bool AActor::GiveAmmo (PClassAmmo *type, int amount) { if (type != NULL) { @@ -5049,19 +5049,19 @@ static fixed_t GetDefaultSpeed(PClassActor *type) // //--------------------------------------------------------------------------- -AActor *P_SpawnMissile (AActor *source, AActor *dest, const PClass *type, AActor *owner) +AActor *P_SpawnMissile (AActor *source, AActor *dest, PClassActor *type, AActor *owner) { return P_SpawnMissileXYZ (source->x, source->y, source->z + 32*FRACUNIT, source, dest, type, true, owner); } -AActor *P_SpawnMissileZ (AActor *source, fixed_t z, AActor *dest, const PClass *type) +AActor *P_SpawnMissileZ (AActor *source, fixed_t z, AActor *dest, PClassActor *type) { return P_SpawnMissileXYZ (source->x, source->y, z, source, dest, type); } AActor *P_SpawnMissileXYZ (fixed_t x, fixed_t y, fixed_t z, - AActor *source, AActor *dest, const PClass *type, bool checkspawn, AActor *owner) + AActor *source, AActor *dest, PClassActor *type, bool checkspawn, AActor *owner) { if (dest == NULL) { @@ -5124,7 +5124,7 @@ AActor *P_SpawnMissileXYZ (fixed_t x, fixed_t y, fixed_t z, return (!checkspawn || P_CheckMissileSpawn (th)) ? th : NULL; } -AActor * P_OldSpawnMissile(AActor * source, AActor * owner, AActor * dest, const PClass *type) +AActor *P_OldSpawnMissile(AActor *source, AActor *owner, AActor *dest, PClassActor *type) { angle_t an; fixed_t dist; diff --git a/src/p_states.cpp b/src/p_states.cpp index cd5543a74..25fd73f70 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -60,7 +60,7 @@ FArchive &operator<< (FArchive &arc, FState *&state) { - const PClassActor *info; + PClassActor *info; if (arc.IsStoring ()) { @@ -94,7 +94,7 @@ FArchive &operator<< (FArchive &arc, FState *&state) } else { - const PClassActor *info; + PClassActor *info; DWORD ofs; arc.UserReadClass<PClassActor>(info); @@ -117,7 +117,7 @@ FArchive &operator<< (FArchive &arc, FState *&state) // //========================================================================== -const PClassActor *FState::StaticFindStateOwner (const FState *state) +PClassActor *FState::StaticFindStateOwner (const FState *state) { for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i) { @@ -139,7 +139,7 @@ const PClassActor *FState::StaticFindStateOwner (const FState *state) // //========================================================================== -const PClassActor *FState::StaticFindStateOwner (const FState *state, const PClassActor *info) +PClassActor *FState::StaticFindStateOwner (const FState *state, PClassActor *info) { while (info != NULL) { diff --git a/src/p_teleport.cpp b/src/p_teleport.cpp index 8fe870e82..50da26824 100644 --- a/src/p_teleport.cpp +++ b/src/p_teleport.cpp @@ -74,7 +74,7 @@ void ATeleportFog::PostBeginPlay () void P_SpawnTeleportFog(fixed_t x, fixed_t y, fixed_t z, int spawnid) { - const PClass *fog=NULL; + PClassActor *fog = NULL; if (spawnid > 0 && spawnid < MAX_SPAWNABLES && SpawnableThings[spawnid] != NULL) { diff --git a/src/p_terrain.h b/src/p_terrain.h index 9c28b3e90..01cbab80b 100644 --- a/src/p_terrain.h +++ b/src/p_terrain.h @@ -81,9 +81,9 @@ struct FSplashDef FName Name; FSoundID SmallSplashSound; FSoundID NormalSplashSound; - const PClass *SmallSplash; - const PClass *SplashBase; - const PClass *SplashChunk; + PClassActor *SmallSplash; + PClassActor *SplashBase; + PClassActor *SplashChunk; BYTE ChunkXVelShift; BYTE ChunkYVelShift; BYTE ChunkZVelShift; diff --git a/src/p_user.cpp b/src/p_user.cpp index e76d706b8..5c7c3f632 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -798,7 +798,7 @@ void APlayerPawn::GiveDeathmatchInventory() AKey *key = (AKey *)GetDefaultByType (PClass::m_Types[i]); if (key->KeyNumber != 0) { - key = static_cast<AKey *>(Spawn (PClass::m_Types[i], 0,0,0, NO_REPLACE)); + key = static_cast<AKey *>(Spawn(static_cast<PClassActor *>(PClass::m_Types[i]), 0,0,0, NO_REPLACE)); if (!key->CallTryPickup (this)) { key->Destroy (); diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 72bfb4d1f..e76597728 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -174,7 +174,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_UnsetFloat) // //========================================================================== static void DoAttack (AActor *self, bool domelee, bool domissile, - int MeleeDamage, FSoundID MeleeSound, const PClass *MissileType,fixed_t MissileHeight) + int MeleeDamage, FSoundID MeleeSound, PClassActor *MissileType,fixed_t MissileHeight) { if (self->target == NULL) return; @@ -189,9 +189,9 @@ static void DoAttack (AActor *self, bool domelee, bool domissile, else if (domissile && MissileType != NULL) { // This seemingly senseless code is needed for proper aiming. - self->z+=MissileHeight-32*FRACUNIT; - AActor * missile = P_SpawnMissileXYZ (self->x, self->y, self->z + 32*FRACUNIT, self, self->target, MissileType, false); - self->z-=MissileHeight-32*FRACUNIT; + self->z += MissileHeight - 32*FRACUNIT; + AActor *missile = P_SpawnMissileXYZ (self->x, self->y, self->z + 32*FRACUNIT, self, self->target, MissileType, false); + self->z -= MissileHeight - 32*FRACUNIT; if (missile) { From 19f5b1dea129e586a2359132d398420829eef0c4 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sun, 4 Apr 2010 02:58:58 +0000 Subject: [PATCH 033/232] - Removed the RUNTIME_TYPE macro. I just included it because MFC has one, but it's pretty pointless here. SVN r2267 (scripting) --- src/actor.h | 2 +- src/dobject.h | 1 - src/farchive.cpp | 2 +- src/g_hexen/a_heresiarch.cpp | 8 ++++---- src/g_shared/a_specialspot.cpp | 8 ++++---- src/g_shared/shared_hud.cpp | 2 +- src/p_acs.cpp | 2 +- src/p_enemy.cpp | 3 +-- src/p_mobj.cpp | 2 +- 9 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/actor.h b/src/actor.h index d1d7f4a0f..50b15d48c 100644 --- a/src/actor.h +++ b/src/actor.h @@ -524,7 +524,7 @@ public: inline AActor *GetDefault () const { - return (AActor *)(RUNTIME_TYPE(this)->Defaults); + return (AActor *)(this->GetClass()->Defaults); } DDropItem *GetDropItems() const; diff --git a/src/dobject.h b/src/dobject.h index 23c284513..93667f9c2 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -80,7 +80,6 @@ class DPillar; class PClassActor; -#define RUNTIME_TYPE(object) (object->GetClass()) // Passed an object, returns the type of that object #define RUNTIME_CLASS_CASTLESS(cls) (cls::RegistrationInfo.MyClass) // Passed a native class name, returns a PClass representing that class #define RUNTIME_CLASS(cls) ((cls::MetaClass *)RUNTIME_CLASS_CASTLESS(cls)) // Like above, but returns the true type of the meta object #define NATIVE_TYPE(object) (object->StaticType()) // Passed an object, returns the type of the C++ class representing the object diff --git a/src/farchive.cpp b/src/farchive.cpp index f2aff5a45..3920479e7 100644 --- a/src/farchive.cpp +++ b/src/farchive.cpp @@ -1043,7 +1043,7 @@ FArchive &FArchive::WriteObject (DObject *obj) } else { - PClass *type = RUNTIME_TYPE(obj); + PClass *type = obj->GetClass(); if (type == RUNTIME_CLASS(DObject)) { diff --git a/src/g_hexen/a_heresiarch.cpp b/src/g_hexen/a_heresiarch.cpp index 62cecea14..2f2065826 100644 --- a/src/g_hexen/a_heresiarch.cpp +++ b/src/g_hexen/a_heresiarch.cpp @@ -285,7 +285,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcBallOrbit) if (!self->IsKindOf (RUNTIME_CLASS(ASorcBall))) { - I_Error ("Corrupted sorcerer:\nTried to use a %s", RUNTIME_TYPE(self)->TypeName.GetChars()); + I_Error ("Corrupted sorcerer:\nTried to use a %s", self->GetClass()->TypeName.GetChars()); } actor = static_cast<ASorcBall *> (self); @@ -317,7 +317,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcBallOrbit) break; case SORC_STOPPING: // Balls stopping - if ((parent->StopBall == RUNTIME_TYPE(actor)) && + if ((parent->StopBall == actor->GetClass()) && (parent->args[1] > SORCBALL_SPEED_ROTATIONS) && (abs(angle - (parent->angle>>ANGLETOFINESHIFT)) < (30<<5))) { @@ -334,7 +334,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcBallOrbit) break; case SORC_FIRESPELL: // Casting spell - if (parent->StopBall == RUNTIME_TYPE(actor)) + if (parent->StopBall == actor->GetClass()) { // Put sorcerer into special throw spell anim if (parent->health > 0) @@ -345,7 +345,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcBallOrbit) break; case SORC_FIRING_SPELL: - if (parent->StopBall == RUNTIME_TYPE(actor)) + if (parent->StopBall == actor->GetClass()) { if (actor->special2-- <= 0) { diff --git a/src/g_shared/a_specialspot.cpp b/src/g_shared/a_specialspot.cpp index 8bf280e78..2e9e5d849 100644 --- a/src/g_shared/a_specialspot.cpp +++ b/src/g_shared/a_specialspot.cpp @@ -263,7 +263,7 @@ FSpotList *DSpotState::FindSpotList(const PClass *type) bool DSpotState::AddSpot(ASpecialSpot *spot) { - FSpotList *list = FindSpotList(RUNTIME_TYPE(spot)); + FSpotList *list = FindSpotList(spot->GetClass()); if (list != NULL) return list->Add(spot); return false; } @@ -276,7 +276,7 @@ bool DSpotState::AddSpot(ASpecialSpot *spot) bool DSpotState::RemoveSpot(ASpecialSpot *spot) { - FSpotList *list = FindSpotList(RUNTIME_TYPE(spot)); + FSpotList *list = FindSpotList(spot->GetClass()); if (list != NULL) return list->Remove(spot); return false; } @@ -393,7 +393,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnSingleItem) AActor *spot = NULL; DSpotState *state = DSpotState::GetSpotState(); - if (state != NULL) spot = state->GetRandomSpot(RUNTIME_TYPE(self), true); + if (state != NULL) spot = state->GetRandomSpot(self->GetClass(), true); if (spot == NULL) return 0; if (!multiplayer && pr_spawnmace() < fail_sp) @@ -429,7 +429,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnSingleItem) } if (spawned->IsKindOf(RUNTIME_CLASS(AInventory))) { - static_cast<AInventory*>(spawned)->SpawnPointClass = RUNTIME_TYPE(self); + static_cast<AInventory*>(spawned)->SpawnPointClass = self->GetClass(); } } return 0; diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 385971d59..f84dc6a8b 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -556,7 +556,7 @@ static void DrawOneWeapon(player_t * CPlayer, int x, int & y, AWeapon * weapon) // Powered up weapons and inherited sister weapons are not displayed. if (weapon->WeaponFlags & WIF_POWERED_UP) return; - if (weapon->SisterWeapon && weapon->IsKindOf(RUNTIME_TYPE(weapon->SisterWeapon))) return; + if (weapon->SisterWeapon && weapon->IsKindOf(weapon->SisterWeapon->GetClass())) return; trans=0x6666; if (CPlayer->ReadyWeapon) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 202eb24ab..9d774493e 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4822,7 +4822,7 @@ int DLevelScript::RunScript () } else if (activator) { - work += RUNTIME_TYPE(activator)->TypeName.GetChars(); + work += activator->GetClass()->TypeName.GetChars(); } else { diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 69146fd99..d71aff711 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -1178,8 +1178,7 @@ bool P_LookForMonsters (AActor *actor) { // Stop searching return false; } - if (mo->IsKindOf (RUNTIME_TYPE(actor)) || - actor->IsKindOf (RUNTIME_TYPE(mo))) + if (mo->IsKindOf (actor->GetClass()) || actor->IsKindOf (mo->GetClass())) { // [RH] Don't go after same species continue; } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 4b38cb93a..2078f9e6c 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -2499,7 +2499,7 @@ void P_NightmareRespawn (AActor *mobj) // spawn it x = mobj->SpawnPoint[0]; y = mobj->SpawnPoint[1]; - mo = Spawn (RUNTIME_TYPE(mobj), x, y, z, NO_REPLACE); + mo = Spawn (mobj->GetClass(), x, y, z, NO_REPLACE); if (z == ONFLOORZ) mo->z += mo->SpawnPoint[2]; From 900324c205aeb963122cb77c790c8b9d42c779e1 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sun, 4 Apr 2010 17:06:04 +0000 Subject: [PATCH 034/232] - Move color sets into the PlayerPawn metadata. SVN r2270 (scripting) --- src/d_netinfo.cpp | 2 +- src/d_player.h | 20 +++++++-- src/info.cpp | 19 -------- src/info.h | 15 ------- src/m_menu.cpp | 18 ++++---- src/p_user.cpp | 65 +++++++++------------------- src/thingdef/thingdef.cpp | 6 --- src/thingdef/thingdef_properties.cpp | 9 ++-- 8 files changed, 53 insertions(+), 101 deletions(-) diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index ac1f77128..1bb709284 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -195,7 +195,7 @@ void D_GetPlayerColor (int player, float *h, float *s, float *v, FPlayerColorSet if (players[player].mo != NULL) { - colorset = P_GetPlayerColorSet(players[player].mo->GetClass()->TypeName, info->colorset); + colorset = players[player].mo->GetClass()->GetColorSet(info->colorset); } if (colorset != NULL) { diff --git a/src/d_player.h b/src/d_player.h index 3453819b0..b3dfe276d 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -46,6 +46,20 @@ class player_t; +// Standard pre-defined skin colors +struct FPlayerColorSet +{ + FName Name; // Name of this color + + int Lump; // Lump to read the translation from, otherwise use next 2 fields + BYTE FirstColor, LastColor; // Describes the range of colors to use for the translation + + BYTE RepresentativeColor; // A palette entry representative of this translation, + // for map arrows and status bar backgrounds and such +}; +typedef TMap<int, FPlayerColorSet> FPlayerColorSetMap; + + class PClassPlayerPawn : public PClassActor { DECLARE_CLASS(PClassPlayerPawn, PClassActor); @@ -53,6 +67,8 @@ protected: virtual void Derive(PClass *newclass); public: PClassPlayerPawn(); + void EnumColorSets(TArray<int> *out); + FPlayerColorSet *GetColorSet(int setnum) { return ColorSets.CheckKey(setnum); } FString DisplayName; // Display name (used in menus, etc.) FString SoundClass; // Sound class @@ -63,11 +79,9 @@ public: fixed_t HexenArmor[5]; BYTE ColorRangeStart; // Skin color range BYTE ColorRangeEnd; + FPlayerColorSetMap ColorSets; }; -FPlayerColorSet *P_GetPlayerColorSet(FName classname, int setnum); -void P_EnumPlayerColorSets(FName classname, TArray<int> *out); - class player_t; class APlayerPawn : public AActor diff --git a/src/info.cpp b/src/info.cpp index 2abe17bed..5804a7857 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -494,25 +494,6 @@ void PClassActor::SetPainChance(FName type, int chance) // //========================================================================== -void PClassActor::SetColorSet(int index, const FPlayerColorSet *set) -{ - if (set != NULL) - { - if (ColorSets == NULL) ColorSets = new FPlayerColorSetMap; - ColorSets->Insert(index, *set); - } - else - { - if (ColorSets != NULL) - ColorSets->Remove(index); - } -} - -//========================================================================== -// -// -//========================================================================== - FDoomEdMap DoomEdMap; FDoomEdMap::FDoomEdEntry *FDoomEdMap::DoomEdHash[DOOMED_HASHSIZE]; diff --git a/src/info.h b/src/info.h index bdeefb53f..a6f37771c 100644 --- a/src/info.h +++ b/src/info.h @@ -123,21 +123,8 @@ FArchive &operator<< (FArchive &arc, FState *&state); #include "gametype.h" -// Standard pre-defined skin colors -struct FPlayerColorSet -{ - FName Name; // Name of this color - - int Lump; // Lump to read the translation from, otherwise use next 2 fields - BYTE FirstColor, LastColor; // Describes the range of colors to use for the translation - - BYTE RepresentativeColor; // A palette entry representative of this translation, - // for map arrows and status bar backgrounds and such -}; - typedef TMap<FName, fixed_t> DmgFactors; typedef TMap<FName, int> PainChanceList; -typedef TMap<int, FPlayerColorSet> FPlayerColorSetMap; class DDropItem; class PClassActor : public PClass @@ -158,7 +145,6 @@ public: void RegisterIDs(); void SetDamageFactor(FName type, fixed_t factor); void SetPainChance(FName type, int chance); - void SetColorSet(int index, const FPlayerColorSet *set); size_t PropagateMark(); void InitializeNativeDefaults(); @@ -182,7 +168,6 @@ public: FStateLabels *StateList; DmgFactors *DamageFactors; PainChanceList *PainChances; - FPlayerColorSetMap *ColorSets; FString Obituary; // Player was killed by this actor FString HitObituary; // Player was killed by this actor in melee fixed_t DeathHeight; // Height on normal death diff --git a/src/m_menu.cpp b/src/m_menu.cpp index 94befe8fe..5d0bdaf2d 100644 --- a/src/m_menu.cpp +++ b/src/m_menu.cpp @@ -2093,7 +2093,7 @@ void M_PlayerSetup (void) } PlayerSkin = players[consoleplayer].userinfo.skin; R_GetPlayerTranslation (players[consoleplayer].userinfo.color, - P_GetPlayerColorSet(PlayerClass->Type->TypeName, players[consoleplayer].userinfo.colorset), + PlayerClass->Type->GetColorSet(players[consoleplayer].userinfo.colorset), &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); PlayerState = GetDefaultByType (PlayerClass->Type)->SeeState; PlayerTics = PlayerState->GetTics(); @@ -2101,7 +2101,7 @@ void M_PlayerSetup (void) { FireTexture = new FBackdropTexture; } - P_EnumPlayerColorSets(PlayerClass->Type->TypeName, &PlayerColorSets); + PlayerClass->Type->EnumColorSets(&PlayerColorSets); } static void M_PlayerSetupTicker (void) @@ -2119,7 +2119,7 @@ static void M_PlayerSetupTicker (void) item = (MenuTime>>2) % (ClassMenuDef.numitems-1); PlayerClass = &PlayerClasses[D_PlayerClassToInt (ClassMenuItems[item].name)]; - P_EnumPlayerColorSets(PlayerClass->Type->TypeName, &PlayerColorSets); + PlayerClass->Type->EnumColorSets(&PlayerColorSets); } else { @@ -2133,7 +2133,7 @@ static void M_PlayerSetupTicker (void) PlayerSkin = R_FindSkin (skins[PlayerSkin].name, int(PlayerClass - &PlayerClasses[0])); R_GetPlayerTranslation (players[consoleplayer].userinfo.color, - P_GetPlayerColorSet(PlayerClass->Type->TypeName, players[consoleplayer].userinfo.colorset), + PlayerClass->Type->GetColorSet(players[consoleplayer].userinfo.colorset), &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); } @@ -2290,7 +2290,7 @@ static void M_PlayerSetupDrawer () } // Draw player color selection and sliders - FPlayerColorSet *colorset = P_GetPlayerColorSet(PlayerClass->Type->TypeName, players[consoleplayer].userinfo.colorset); + FPlayerColorSet *colorset = PlayerClass->Type->GetColorSet(players[consoleplayer].userinfo.colorset); x = SmallFont->StringWidth("Color") + 8 + PSetupDef.x; screen->DrawText(SmallFont, label, PSetupDef.x, PSetupDef.y + LINEHEIGHT*2+yo, "Color", DTA_Clean, true, TAG_DONE); screen->DrawText(SmallFont, value, x, PSetupDef.y + LINEHEIGHT*2+yo, @@ -2604,7 +2604,7 @@ static void M_ChangeSkin (int choice) } while (!PlayerClass->CheckSkin (PlayerSkin)); R_GetPlayerTranslation (players[consoleplayer].userinfo.color, - P_GetPlayerColorSet(PlayerClass->Type->TypeName, players[consoleplayer].userinfo.colorset), + PlayerClass->Type->GetColorSet(players[consoleplayer].userinfo.colorset), &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); cvar_set ("skin", skins[PlayerSkin].name); @@ -2762,7 +2762,7 @@ static void M_ChangeColorSet (int choice) mysnprintf(command, countof(command), "colorset %d", mycolorset); C_DoCommand(command); R_GetPlayerTranslation(players[consoleplayer].userinfo.color, - P_GetPlayerColorSet(PlayerClass->Type->TypeName, mycolorset), + PlayerClass->Type->GetColorSet(mycolorset), &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); } @@ -2773,7 +2773,7 @@ static void SendNewColor (int red, int green, int blue) mysnprintf (command, countof(command), "color \"%02x %02x %02x\"", red, green, blue); C_DoCommand (command); R_GetPlayerTranslation(MAKERGB (red, green, blue), - P_GetPlayerColorSet(PlayerClass->Type->TypeName, players[consoleplayer].userinfo.colorset), + PlayerClass->Type->GetColorSet(players[consoleplayer].userinfo.colorset), &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); } @@ -4116,5 +4116,5 @@ static void PickPlayerClass () } PlayerClass = &PlayerClasses[pclass]; - P_EnumPlayerColorSets(PlayerClass->Type->TypeName, &PlayerColorSets); + PlayerClass->Type->EnumColorSets(&PlayerColorSets); } diff --git a/src/p_user.cpp b/src/p_user.cpp index f2ee29234..b3973a8fa 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -421,6 +421,7 @@ void PClassPlayerPawn::Derive(PClass *newclass) newp->HealingRadiusType = HealingRadiusType; newp->ColorRangeStart = ColorRangeStart; newp->ColorRangeEnd = ColorRangeEnd; + newp->ColorSets = ColorSets; for (i = 0; i < countof(HexenArmor); ++i) { newp->HexenArmor[i] = HexenArmor[i]; @@ -431,6 +432,25 @@ void PClassPlayerPawn::Derive(PClass *newclass) } } +static int STACK_ARGS intcmp(const void *a, const void *b) +{ + return *(const int *)a - *(const int *)b; +} + +void PClassPlayerPawn::EnumColorSets(TArray<int> *out) +{ + out->Clear(); + FPlayerColorSetMap::Iterator it(ColorSets); + FPlayerColorSetMap::Pair *pair; + + while (it.NextPair(pair)) + { + out->Push(pair->Key); + } + qsort(&(*out)[0], out->Size(), sizeof(int), intcmp); +} + + //=========================================================================== // // APlayerPawn @@ -2669,48 +2689,3 @@ void player_t::Serialize (FArchive &arc) original_oldbuttons = ~0; } } - - -static FPlayerColorSetMap *GetPlayerColors(FName classname) -{ - PClassPlayerPawn *cls = dyn_cast<PClassPlayerPawn>(PClass::FindClass(classname)); - - if (cls != NULL) - { - return cls->ColorSets; - } - return NULL; -} - -FPlayerColorSet *P_GetPlayerColorSet(FName classname, int setnum) -{ - FPlayerColorSetMap *map = GetPlayerColors(classname); - if (map == NULL) - { - return NULL; - } - return map->CheckKey(setnum); -} - -static int STACK_ARGS intcmp(const void *a, const void *b) -{ - return *(const int *)a - *(const int *)b; -} - -void P_EnumPlayerColorSets(FName classname, TArray<int> *out) -{ - out->Clear(); - FPlayerColorSetMap *map = GetPlayerColors(classname); - if (map != NULL) - { - FPlayerColorSetMap::Iterator it(*map); - FPlayerColorSetMap::Pair *pair; - - while (it.NextPair(pair)) - { - out->Push(pair->Key); - } - qsort(&(*out)[0], out->Size(), sizeof(int), intcmp); - } -} - diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index d9667fb07..4cc1b9bf7 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -153,12 +153,6 @@ PClassActor *CreateNewActor(const FScriptPosition &sc, FName typeName, FName par ti->PainChances = new PainChanceList; *ti->PainChances = *parent->PainChances; } - if (parent->ColorSets != NULL) - { - // copy color sets from parent - ti->ColorSets = new FPlayerColorSetMap; - *ti->ColorSets = *parent->ColorSets; - } ti->Replacee = ti->Replacement = NULL; ti->DoomEdNum = -1; return ti; diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index c6f4c285c..ef147b183 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -1931,7 +1931,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorset, ISIII, PlayerPawn) } else { - info->SetColorSet(setnum, &color); + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); + static_cast<PClassPlayerPawn *>(info)->ColorSets.Insert(setnum, color); } } @@ -1955,7 +1956,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorsetfile, ISSI, PlayerPawn) } else if (color.Lump >= 0) { - info->SetColorSet(setnum, &color); + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); + static_cast<PClassPlayerPawn *>(info)->ColorSets.Insert(setnum, color); } } @@ -1972,7 +1974,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, clearcolorset, I, PlayerPawn) } else { - info->SetColorSet(setnum, NULL); + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); + static_cast<PClassPlayerPawn *>(info)->ColorSets.Remove(setnum); } } From ee55e0319f780bc8dd7b4c38c1d40bcf375cb266 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 16 Apr 2010 02:57:51 +0000 Subject: [PATCH 035/232] - Standardized use of PClassActor::AllActorClasses for iterating over all classes of actors instead of PClass::m_Types (now PClass::AllClasses). - Removed ClassIndex from PClass. It was only needed by FArchive, and maps take care of the problem just as well. - Moved PClass into a larger type system (which is likely to change some/lots once I try and actually use it and have a better feel for what I need from it). SVN r2281 (scripting) --- src/d_dehacked.cpp | 4 +- src/d_main.cpp | 6 +- src/decallib.cpp | 4 +- src/dobject.cpp | 4 +- src/dobject.h | 25 +- src/dobjgc.cpp | 20 +- src/dobjtype.cpp | 823 +++++++++++++++++++++++---- src/dobjtype.h | 347 ++++++++++- src/farchive.cpp | 131 ++--- src/farchive.h | 24 +- src/g_shared/a_keys.cpp | 16 +- src/g_shared/a_pickups.cpp | 4 +- src/g_shared/a_weapons.cpp | 8 +- src/g_shared/sbarinfo_commands.cpp | 6 +- src/g_shared/shared_hud.cpp | 4 +- src/info.cpp | 12 +- src/info.h | 3 + src/m_cheat.cpp | 58 +- src/namedef.h | 2 + src/p_states.cpp | 8 +- src/p_user.cpp | 8 +- src/tarray.h | 16 + src/thingdef/thingdef.cpp | 9 +- src/thingdef/thingdef_expression.cpp | 12 +- 24 files changed, 1204 insertions(+), 350 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 8f4615683..decd07b05 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -1453,9 +1453,9 @@ static int PatchAmmo (int ammoNum) // Fix per-ammo/max-ammo amounts for descendants of the base ammo class if (oldclip != *per) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClass *type = PClass::m_Types[i]; + PClassActor *type = PClassActor::AllActorClasses[i]; if (type == ammoType) continue; diff --git a/src/d_main.cpp b/src/d_main.cpp index 3b4228a68..2f0c071fe 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1754,14 +1754,16 @@ void D_DoomMain (void) #endif #endif + PClass::StaticInit(); + PType::StaticInit(); + // Combine different file parameters with their pre-switch bits. Args->CollectFiles("-deh", ".deh"); Args->CollectFiles("-bex", ".bex"); Args->CollectFiles("-exec", ".cfg"); Args->CollectFiles("-playdemo", ".lmp"); - Args->CollectFiles("-file", NULL); // anythnig left goes after -file + Args->CollectFiles("-file", NULL); // anything left goes after -file - PClass::StaticInit (); atterm (C_DeinitConsole); gamestate = GS_STARTUP; diff --git a/src/decallib.cpp b/src/decallib.cpp index 6446f9283..8e06778b4 100644 --- a/src/decallib.cpp +++ b/src/decallib.cpp @@ -353,9 +353,9 @@ void FDecalLib::ReadAllDecals () ReadDecals (sc); } // Supporting code to allow specifying decals directly in the DECORATE lump - for (i = 0; i < PClass::m_RuntimeActors.Size(); i++) + for (i = 0; i < PClassActor::AllActorClasses.Size(); i++) { - AActor *def = (AActor*)GetDefaultByType (PClass::m_RuntimeActors[i]); + AActor *def = (AActor*)GetDefaultByType (PClassActor::AllActorClasses[i]); FName v = ENamedName(intptr_t(def->DecalGenerator)); if (v.IsValidName()) diff --git a/src/dobject.cpp b/src/dobject.cpp index 959b25d58..d9d94aa34 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -180,9 +180,9 @@ CCMD (dumpclasses) shown = omitted = 0; DumpInfo::AddType (&tree, root != NULL ? root : RUNTIME_CLASS(DObject)); - for (i = 0; i < PClass::m_Types.Size(); i++) + for (i = 0; i < PClass::AllClasses.Size(); i++) { - PClass *cls = PClass::m_Types[i]; + PClass *cls = PClass::AllClasses[i]; if (root == NULL || cls == root || cls->IsDescendantOf(root)) { DumpInfo::AddType (&tree, cls); diff --git a/src/dobject.h b/src/dobject.h index 93667f9c2..ad4481f5a 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -94,7 +94,9 @@ enum CLASSREG_PClassHealth, CLASSREG_PClassPuzzleItem, CLASSREG_PClassWeapon, - CLASSREG_PClassPlayerPawn + CLASSREG_PClassPlayerPawn, + CLASSREG_PClassType, + CLASSREG_PClassClass, }; struct ClassReg @@ -104,10 +106,11 @@ struct ClassReg ClassReg *ParentType; const size_t *Pointers; void (*ConstructNative)(void *); - unsigned int SizeOf:29; - unsigned int MetaClassNum:3; + unsigned int SizeOf:28; + unsigned int MetaClassNum:4; PClass *RegisterClass(); + void SetupClass(PClass *cls); }; enum EInPlace { EC_InPlace }; @@ -178,6 +181,10 @@ protected: \ #define IMPLEMENT_ABSTRACT_CLASS(cls) \ _IMP_PCLASS(cls,NULL,NULL) +#define IMPLEMENT_ABSTRACT_POINTY_CLASS(cls) \ + _IMP_PCLASS(cls,cls::PointerOffsets,NULL) \ + const size_t cls::PointerOffsets[] = { + enum EObjectFlags { // GC flags @@ -292,6 +299,9 @@ namespace GC // is NULLed instead. void Mark(DObject **obj); + // Marks an array of objects. + void MarkArray(DObject **objs, size_t count); + // Soft-roots an object. void AddSoftRoot(DObject *obj); @@ -310,6 +320,15 @@ namespace GC obj = t; } template<class T> void Mark(TObjPtr<T> &obj); + + template<class T> void MarkArray(T **obj, size_t count) + { + MarkArray((DObject **)(obj), count); + } + template<class T> void MarkArray(TArray<T> &arr) + { + MarkArray(&arr[0], arr.Size()); + } } // A template class to help with handling read barriers. It does not diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index 3bdca01bd..105ec1096 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -283,6 +283,22 @@ void Mark(DObject **obj) } } +//========================================================================== +// +// MarkArray +// +// Mark an array of objects gray. +// +//========================================================================== + +void MarkArray(DObject **obj, size_t count) +{ + for (size_t i = 0; i < count; ++i) + { + Mark(obj[i]); + } +} + //========================================================================== // // MarkRoot @@ -341,9 +357,9 @@ static void MarkRoot() } } // Mark classes - for (unsigned j = 0; j < PClass::m_Types.Size(); ++j) + for (unsigned j = 0; j < PClass::AllClasses.Size(); ++j) { - Mark(PClass::m_Types[j]); + Mark(PClass::AllClasses[j]); } // Mark bot stuff. Mark(bglobal.firstthing); diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index d2ec92d15..a211c55da 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -3,7 +3,7 @@ ** Implements the type information class ** **--------------------------------------------------------------------------- -** Copyright 1998-2008 Randy Heit +** Copyright 1998-2010 Randy Heit ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -32,6 +32,8 @@ ** */ +// HEADER FILES ------------------------------------------------------------ + #include "dobject.h" #include "i_system.h" #include "actor.h" @@ -41,17 +43,425 @@ #include "a_pickups.h" #include "d_player.h" +// MACROS ------------------------------------------------------------------ + +// TYPES ------------------------------------------------------------------- + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +FTypeTable TypeTable; +TArray<PClass *> PClass::AllClasses; +bool PClass::bShutdown; + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +// A harmless non-NULL FlatPointer for classes without pointers. +static const size_t TheEnd = ~(size_t)0; + +// CODE -------------------------------------------------------------------- + +void DumpTypeTable() +{ + int used = 0; + int min = INT_MAX; + int max = 0; + int all = 0; + int lens[10] = {0}; + for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i) + { + int len = 0; + Printf("%4d:", i); + for (PType *ty = TypeTable.TypeHash[i]; ty != NULL; ty = ty->HashNext) + { + Printf(" -> %s", ty->IsKindOf(RUNTIME_CLASS(PNamedType)) ? static_cast<PNamedType*>(ty)->TypeName.GetChars(): ty->GetClass()->TypeName.GetChars()); + len++; + all++; + } + if (len != 0) + { + used++; + if (len < min) + min = len; + if (len > max) + max = len; + } + if (len < countof(lens)) + { + lens[len]++; + } + Printf("\n"); + } + Printf("Used buckets: %d/%u (%.2f%%) for %d entries\n", used, countof(TypeTable.TypeHash), double(used)/countof(TypeTable.TypeHash)*100, all); + Printf("Min bucket size: %d\n", min); + Printf("Max bucket size: %d\n", max); + Printf("Avg bucket size: %.2f\n", double(all) / used); + int j,k; + for (k = k = countof(lens)-1; k > 0; --k) + if (lens[k]) + break; + for (j = 0; j <= k; ++j) + Printf("Buckets of len %d: %d (%.2f%%)\n", j, lens[j], j!=0?double(lens[j])/used*100:-1.0); +} + +/* PClassType *************************************************************/ + +IMPLEMENT_CLASS(PClassType) + +//========================================================================== +// +// PClassType Constructor +// +//========================================================================== + +PClassType::PClassType() +: TypeTableType(NULL) +{ +} + +//========================================================================== +// +// PClassType :: Derive +// +//========================================================================== + +void PClassType::Derive(PClass *newclass) +{ + assert(newclass->IsKindOf(RUNTIME_CLASS(PClassType))); + Super::Derive(newclass); + static_cast<PClassType *>(newclass)->TypeTableType = TypeTableType; +} + +/* PClassClass ************************************************************/ + +IMPLEMENT_CLASS(PClassClass) + +//========================================================================== +// +// PClassClass Constructor +// +// The only thing we want to do here is automatically set TypeTableType +// to PClass. +// +//========================================================================== + +PClassClass::PClassClass() +{ + TypeTableType = RUNTIME_CLASS(PClass); +} + +/* PType ******************************************************************/ + +IMPLEMENT_ABSTRACT_CLASS(PType) + +//========================================================================== +// +// PType Constructor +// +//========================================================================== + +PType::PType() +: Size(0), Align(1), HashNext(NULL) +{ +} + +//========================================================================== +// +// PType Destructor +// +//========================================================================== + +PType::~PType() +{ +} + +//========================================================================== +// +// PType :: IsMatch +// +//========================================================================== + +bool PType::IsMatch(const void *id1, const void *id2) const +{ + return false; +} + +//========================================================================== +// +// PType :: StaticInit STATIC +// +// Set up TypeTableType values for every PType child. +// +//========================================================================== + +void PType::StaticInit() +{ + RUNTIME_CLASS(PInt)->TypeTableType = RUNTIME_CLASS(PInt); + RUNTIME_CLASS(PFloat)->TypeTableType = RUNTIME_CLASS(PFloat); + RUNTIME_CLASS(PString)->TypeTableType = RUNTIME_CLASS(PString); + RUNTIME_CLASS(PName)->TypeTableType = RUNTIME_CLASS(PName); + RUNTIME_CLASS(PSound)->TypeTableType = RUNTIME_CLASS(PSound); + RUNTIME_CLASS(PColor)->TypeTableType = RUNTIME_CLASS(PColor); + RUNTIME_CLASS(PPointer)->TypeTableType = RUNTIME_CLASS(PPointer); + RUNTIME_CLASS(PClassPointer)->TypeTableType = RUNTIME_CLASS(PPointer); // not sure about this yet + RUNTIME_CLASS(PEnum)->TypeTableType = RUNTIME_CLASS(PEnum); + RUNTIME_CLASS(PArray)->TypeTableType = RUNTIME_CLASS(PArray); + RUNTIME_CLASS(PDynArray)->TypeTableType = RUNTIME_CLASS(PDynArray); + RUNTIME_CLASS(PVector)->TypeTableType = RUNTIME_CLASS(PVector); + RUNTIME_CLASS(PMap)->TypeTableType = RUNTIME_CLASS(PMap); + RUNTIME_CLASS(PStruct)->TypeTableType = RUNTIME_CLASS(PStruct); + RUNTIME_CLASS(PPrototype)->TypeTableType = RUNTIME_CLASS(PPrototype); + RUNTIME_CLASS(PFunction)->TypeTableType = RUNTIME_CLASS(PFunction); + RUNTIME_CLASS(PClass)->TypeTableType = RUNTIME_CLASS(PClass); +} + + +/* PBasicType *************************************************************/ + +IMPLEMENT_ABSTRACT_CLASS(PBasicType) + +/* PCompoundType **********************************************************/ + +IMPLEMENT_ABSTRACT_CLASS(PCompoundType) + +/* PNamedType *************************************************************/ + +IMPLEMENT_ABSTRACT_POINTY_CLASS(PNamedType) + DECLARE_POINTER(Outer) +END_POINTERS + +//========================================================================== +// +// PNamedType :: IsMatch +// +//========================================================================== + +bool PNamedType::IsMatch(const void *id1, const void *id2) const +{ + const DObject *outer = (const DObject *)id1; + FName name = (ENamedName)(intptr_t)id2; + + return Outer == outer && TypeName == name; +} + +/* PInt *******************************************************************/ + +IMPLEMENT_CLASS(PInt) + +/* PFloat *****************************************************************/ + +IMPLEMENT_CLASS(PFloat) + +/* PString ****************************************************************/ + +IMPLEMENT_CLASS(PString) + +/* PName ******************************************************************/ + +IMPLEMENT_CLASS(PName) + +/* PSound *****************************************************************/ + +IMPLEMENT_CLASS(PSound) + +/* PColor *****************************************************************/ + +IMPLEMENT_CLASS(PColor) + +/* PPointer ***************************************************************/ + +IMPLEMENT_POINTY_CLASS(PPointer) + DECLARE_POINTER(PointedType) +END_POINTERS + +//========================================================================== +// +// PPointer :: IsMatch +// +//========================================================================== + +bool PPointer::IsMatch(const void *id1, const void *id2) const +{ + assert(id2 == NULL); + PType *pointat = (PType *)id1; + + return pointat == PointedType; +} + +/* PClassPointer **********************************************************/ + +IMPLEMENT_POINTY_CLASS(PClassPointer) + DECLARE_POINTER(ClassRestriction) +END_POINTERS + +//========================================================================== +// +// PClassPointer :: IsMatch +// +//========================================================================== + +bool PClassPointer::IsMatch(const void *id1, const void *id2) const +{ + const PType *pointat = (const PType *)id1; + const PClass *classat = (const PClass *)id2; + + assert(pointat->IsKindOf(RUNTIME_CLASS(PClass))); + return classat == ClassRestriction; +} + +/* PEnum ******************************************************************/ + +IMPLEMENT_POINTY_CLASS(PEnum) + DECLARE_POINTER(ValueType) +END_POINTERS + +/* PArray *****************************************************************/ + +IMPLEMENT_POINTY_CLASS(PArray) + DECLARE_POINTER(ElementType) +END_POINTERS + +//========================================================================== +// +// PArray :: IsMatch +// +//========================================================================== + +bool PArray::IsMatch(const void *id1, const void *id2) const +{ + const PType *elemtype = (const PType *)id1; + unsigned int count = (unsigned int)(intptr_t)id2; + + return elemtype == ElementType && count == ElementCount; +} + +/* PVector ****************************************************************/ + +IMPLEMENT_CLASS(PVector) + +/* PDynArray **************************************************************/ + +IMPLEMENT_POINTY_CLASS(PDynArray) + DECLARE_POINTER(ElementType) +END_POINTERS + +bool PDynArray::IsMatch(const void *id1, const void *id2) const +{ + assert(id2 == NULL); + const PType *elemtype = (const PType *)id1; + + return elemtype == ElementType; +} + +/* PMap *******************************************************************/ + +IMPLEMENT_POINTY_CLASS(PMap) + DECLARE_POINTER(KeyType) + DECLARE_POINTER(ValueType) +END_POINTERS + +//========================================================================== +// +// PMap :: IsMatch +// +//========================================================================== + +bool PMap::IsMatch(const void *id1, const void *id2) const +{ + const PType *keyty = (const PType *)id1; + const PType *valty = (const PType *)id2; + + return keyty == KeyType && valty == ValueType; +} + +/* PStruct ****************************************************************/ + +IMPLEMENT_CLASS(PStruct) + +//========================================================================== +// +// PStruct :: PropagateMark +// +//========================================================================== + +size_t PStruct::PropagateMark() +{ + GC::MarkArray(Fields); + return Fields.Size() * sizeof(void*) + Super::PropagateMark(); +} + +/* PPrototype *************************************************************/ + +IMPLEMENT_CLASS(PPrototype) + +//========================================================================== +// +// PPrototype :: IsMatch +// +//========================================================================== + +bool PPrototype::IsMatch(const void *id1, const void *id2) const +{ + const TArray<PType *> *args = (const TArray<PType *> *)id1; + const TArray<PType *> *rets = (const TArray<PType *> *)id2; + + return *args == ArgumentTypes && *rets == ReturnTypes; +} + +//========================================================================== +// +// PPrototype :: PropagateMark +// +//========================================================================== + +size_t PPrototype::PropagateMark() +{ + GC::MarkArray(ArgumentTypes); + GC::MarkArray(ReturnTypes); + return (ArgumentTypes.Size() + ReturnTypes.Size()) * sizeof(void*) + + Super::PropagateMark(); +} + +/* PFunction **************************************************************/ + +IMPLEMENT_CLASS(PFunction) + +//========================================================================== +// +// PFunction :: PropagataMark +// +//========================================================================== + +size_t PFunction::PropagateMark() +{ + for (unsigned i = 0; i < Variants.Size(); ++i) + { + GC::Mark(Variants[i].Proto); + GC::Mark(Variants[i].Implementation); + } + return Variants.Size() * sizeof(Variants[0]) + Super::PropagateMark(); +} + +/* PClass *****************************************************************/ + IMPLEMENT_POINTY_CLASS(PClass) DECLARE_POINTER(ParentClass) END_POINTERS -TArray<PClassActor *> PClass::m_RuntimeActors; -TArray<PClass *> PClass::m_Types; -PClass *PClass::TypeHash[PClass::HASH_SIZE]; -bool PClass::bShutdown; - -// A harmless non-NULL FlatPointer for classes without pointers. -static const size_t TheEnd = ~(size_t)0; +//========================================================================== +// +// cregcmp +// +// Sorter to keep built-in types in a deterministic order. (Needed?) +// +//========================================================================== static int STACK_ARGS cregcmp (const void *a, const void *b) { @@ -60,10 +470,20 @@ static int STACK_ARGS cregcmp (const void *a, const void *b) return strcmp(class1->TypeName, class2->TypeName); } +//========================================================================== +// +// PClass :: StaticInit STATIC +// +// Creates class metadata for all built-in types. +// +//========================================================================== + void PClass::StaticInit () { atterm (StaticShutdown); + StaticBootstrap(); + FAutoSegIterator probe(CRegHead, CRegTail); while (*++probe != NULL) @@ -71,24 +491,29 @@ void PClass::StaticInit () ((ClassReg *)*probe)->RegisterClass (); } - // Keep actors in consistant order. I did this before, though I'm not - // sure if this is really necessary to maintain any sort of sync. - qsort(&m_Types[0], m_Types.Size(), sizeof(m_Types[0]), cregcmp); - for (unsigned int i = 0; i < m_Types.Size(); ++i) - { - m_Types[i]->ClassIndex = i; - } + // Keep built-in classes in consistant order. I did this before, though + // I'm not sure if this is really necessary to maintain any sort of sync. + qsort(&AllClasses[0], AllClasses.Size(), sizeof(AllClasses[0]), cregcmp); } +//========================================================================== +// +// PClass :: StaticShutdown STATIC +// +// Frees FlatPointers belonging to all classes. Only really needed to avoid +// memory leak warnings at exit. +// +//========================================================================== + void PClass::StaticShutdown () { TArray<size_t *> uniqueFPs(64); unsigned int i, j; - for (i = 0; i < PClass::m_Types.Size(); ++i) + for (i = 0; i < PClass::AllClasses.Size(); ++i) { - PClass *type = PClass::m_Types[i]; - PClass::m_Types[i] = NULL; + PClass *type = PClass::AllClasses[i]; + PClass::AllClasses[i] = NULL; if (type->FlatPointers != &TheEnd && type->FlatPointers != type->Pointers) { // FlatPointers are shared by many classes, so we must check for @@ -113,6 +538,43 @@ void PClass::StaticShutdown () bShutdown = true; } +//========================================================================== +// +// PClass :: StaticBootstrap STATIC +// +// PClass and PClassClass have intermingling dependencies on their +// definitions. To sort this out, we explicitly define them before +// proceeding with the RegisterClass loop in StaticInit(). +// +//========================================================================== + +void PClass::StaticBootstrap() +{ + PClassClass *clscls = new PClassClass; + PClassClass::RegistrationInfo.SetupClass(clscls); + + PClassClass *cls = new PClassClass; + PClass::RegistrationInfo.SetupClass(cls); + + // The PClassClass constructor initialized these to NULL, because the + // PClass metadata had not been created yet. Now it has, so we know what + // they should be and can insert them into the type table successfully. + clscls->TypeTableType = cls; + cls->TypeTableType = cls; + clscls->InsertIntoHash(); + cls->InsertIntoHash(); + + // Create parent objects before we go so that these definitions are complete. + clscls->ParentClass = PClassType::RegistrationInfo.ParentType->RegisterClass(); + cls->ParentClass = PClass::RegistrationInfo.ParentType->RegisterClass(); +} + +//========================================================================== +// +// PClass Constructor +// +//========================================================================== + PClass::PClass() { Size = sizeof(DObject); @@ -122,10 +584,17 @@ PClass::PClass() HashNext = NULL; Defaults = NULL; bRuntimeClass = false; - ClassIndex = ~0; ConstructNative = NULL; + + PClass::AllClasses.Push(this); } +//========================================================================== +// +// PClass Destructor +// +//========================================================================== + PClass::~PClass() { Symbols.ReleaseSymbols(); @@ -136,6 +605,15 @@ PClass::~PClass() } } +//========================================================================== +// +// ClassReg :: RegisterClass +// +// Create metadata describing the built-in class this struct is intended +// for. +// +//========================================================================== + PClass *ClassReg::RegisterClass() { static ClassReg *const metaclasses[] = @@ -148,10 +626,11 @@ PClass *ClassReg::RegisterClass() &PClassPuzzleItem::RegistrationInfo, &PClassWeapon::RegistrationInfo, &PClassPlayerPawn::RegistrationInfo, + &PClassType::RegistrationInfo, + &PClassClass::RegistrationInfo, }; - // MyClass may have already been created by a previous recursive call. - // Or this may be a recursive call for a previously created class. + // Skip classes that have already been registered if (MyClass != NULL) { return MyClass; @@ -165,25 +644,13 @@ PClass *ClassReg::RegisterClass() assert(0 && "Class registry has an invalid meta class identifier"); } - if (this == &PClass::RegistrationInfo) - { - cls = new PClass; - } - else - { - if (metaclasses[MetaClassNum]->MyClass == NULL) - { // Make sure the meta class is already registered before registering this one - metaclasses[MetaClassNum]->RegisterClass(); - } - cls = static_cast<PClass *>(metaclasses[MetaClassNum]->MyClass->CreateNew()); + if (metaclasses[MetaClassNum]->MyClass == NULL) + { // Make sure the meta class is already registered before registering this one + metaclasses[MetaClassNum]->RegisterClass(); } + cls = static_cast<PClass *>(metaclasses[MetaClassNum]->MyClass->CreateNew()); - MyClass = cls; - PClass::m_Types.Push(cls); - cls->TypeName = FName(Name+1); - cls->Size = SizeOf; - cls->Pointers = Pointers; - cls->ConstructNative = ConstructNative; + SetupClass(cls); cls->InsertIntoHash(); if (ParentType != NULL) { @@ -192,65 +659,76 @@ PClass *ClassReg::RegisterClass() return cls; } -void PClass::InsertIntoHash () -{ - // Add class to hash table. Classes are inserted into each bucket - // in ascending order by name index. - unsigned int bucket = TypeName % HASH_SIZE; - PClass **hashpos = &TypeHash[bucket]; - while (*hashpos != NULL) - { - int lexx = int(TypeName) - int((*hashpos)->TypeName); +//========================================================================== +// +// ClassReg :: SetupClass +// +// Copies the class-defining parameters from a ClassReg to the Class object +// created for it. +// +//========================================================================== - if (lexx > 0) - { // This type should come later in the chain - hashpos = &((*hashpos)->HashNext); - } - else if (lexx == 0) - { // This type has already been inserted - // ... but there is no need whatsoever to make it a fatal error! - Printf (TEXTCOLOR_RED"Tried to register class '%s' more than once.\n", TypeName.GetChars()); - break; - } - else - { // Type comes right here - break; - } - } - HashNext = *hashpos; - *hashpos = this; +void ClassReg::SetupClass(PClass *cls) +{ + assert(MyClass == NULL); + MyClass = cls; + cls->TypeName = FName(Name+1); + cls->Size = SizeOf; + cls->Pointers = Pointers; + cls->ConstructNative = ConstructNative; } -// Find a type, passed the name as a name +//========================================================================== +// +// PClass :: InsertIntoHash +// +// Add class to the type table. +// +//========================================================================== + +void PClass::InsertIntoHash () +{ + size_t bucket; + PType *found; + + found = TypeTable.FindType(RUNTIME_CLASS(PClass), Outer, (void*)(intptr_t)(int)TypeName, &bucket); + if (found != NULL) + { // This type has already been inserted + // ... but there is no need whatsoever to make it a fatal error! + Printf (TEXTCOLOR_RED"Tried to register class '%s' more than once.\n", TypeName.GetChars()); + } + else + { + TypeTable.AddType(this, RUNTIME_CLASS(PClass), Outer, (void*)(intptr_t)(int)TypeName, bucket); + } +} + +//========================================================================== +// +// PClass :: FindClass +// +// Find a type, passed the name as a name. +// +//========================================================================== + PClass *PClass::FindClass (FName zaname) { if (zaname == NAME_None) { return NULL; } - - PClass *cls = TypeHash[zaname % HASH_SIZE]; - - while (cls != 0) - { - int lexx = int(zaname) - int(cls->TypeName); - if (lexx > 0) - { - cls = cls->HashNext; - } - else if (lexx == 0) - { - return cls->Size<0? NULL : cls; - } - else - { - break; - } - } - return NULL; + return static_cast<PClass *>(TypeTable.FindType(RUNTIME_CLASS(PClass), + /*FIXME:Outer*/NULL, (void*)(intptr_t)(int)zaname, NULL)); } +//========================================================================== +// +// PClass :: CreateNew +// // Create a new object that this class represents +// +//========================================================================== + DObject *PClass::CreateNew() const { BYTE *mem = (BYTE *)M_Malloc (Size); @@ -267,7 +745,14 @@ DObject *PClass::CreateNew() const return (DObject *)mem; } +//========================================================================== +// +// PClass :: Derive +// // Copies inheritable values into the derived class and other miscellaneous setup. +// +//========================================================================== + void PClass::Derive(PClass *newclass) { newclass->ParentClass = this; @@ -275,7 +760,7 @@ void PClass::Derive(PClass *newclass) // Set up default instance of the new class. newclass->Defaults = (BYTE *)M_Malloc(newclass->Size); - memcpy(newclass->Defaults, Defaults, Size); + if (Defaults) memcpy(newclass->Defaults, Defaults, Size); if (newclass->Size > Size) { memset(newclass->Defaults + Size, 0, newclass->Size - Size); @@ -284,8 +769,15 @@ void PClass::Derive(PClass *newclass) newclass->Symbols.SetParentTable(&this->Symbols); } +//========================================================================== +// +// PClass :: CreateDerivedClass +// // Create a new class based on an existing class -PClass *PClass::CreateDerivedClass (FName name, unsigned int size) +// +//========================================================================== + +PClass *PClass::CreateDerivedClass(FName name, unsigned int size) { assert (size >= Size); PClass *type; @@ -317,20 +809,20 @@ PClass *PClass::CreateDerivedClass (FName name, unsigned int size) Derive(type); if (!notnew) { - type->ClassIndex = m_Types.Push (type); type->InsertIntoHash(); } - - // If this class is for an actor, push it onto the RuntimeActors stack. - if (type->IsKindOf(RUNTIME_CLASS(PClassActor))) - { - m_RuntimeActors.Push(static_cast<PClassActor *>(type)); - } return type; } -// Add <extension> bytes to the end of this class. Returns the -// previous size of the class. +//========================================================================== +// +// PClass:: Extend +// +// Add <extension> bytes to the end of this class. Returns the previous +// size of the class. +// +//========================================================================== + unsigned int PClass::Extend(unsigned int extension) { assert(this->bRuntimeClass); @@ -342,33 +834,30 @@ unsigned int PClass::Extend(unsigned int extension) return oldsize; } -// Like FindClass but creates a placeholder if no class -// is found. CreateDerivedClass will automatcally fill in -// the placeholder when the actual class is defined. -PClass *PClass::FindClassTentative (FName name) +//========================================================================== +// +// PClass :: FindClassTentative +// +// Like FindClass but creates a placeholder if no class is found. +// CreateDerivedClass will automatically fill in the placeholder when the +// actual class is defined. +// +//========================================================================== + +PClass *PClass::FindClassTentative(FName name) { if (name == NAME_None) { return NULL; } + size_t bucket; - PClass *cls = TypeHash[name % HASH_SIZE]; + PType *found = TypeTable.FindType(RUNTIME_CLASS(PClass), + /*FIXME:Outer*/NULL, (void*)(intptr_t)(int)name, &bucket); - while (cls != 0) + if (found != NULL) { - int lexx = int(name) - int(cls->TypeName); - if (lexx > 0) - { - cls = cls->HashNext; - } - else if (lexx == 0) - { - return cls; - } - else - { - break; - } + return static_cast<PClass *>(found); } PClass *type = static_cast<PClass *>(GetClass()->CreateNew()); DPrintf("Creating placeholder class %s : %s\n", name.GetChars(), TypeName.GetChars()); @@ -376,16 +865,22 @@ PClass *PClass::FindClassTentative (FName name) type->TypeName = name; type->ParentClass = this; type->Size = -1; - type->ClassIndex = m_Types.Push (type); type->bRuntimeClass = true; - type->InsertIntoHash(); + TypeTable.AddType(type, RUNTIME_CLASS(PClass), type->Outer, (void*)(intptr_t)(int)name, bucket); return type; } +//========================================================================== +// +// PClass :: BuildFlatPointers +// // Create the FlatPointers array, if it doesn't exist already. -// It comprises all the Pointers from superclasses plus this class's own Pointers. -// If this class does not define any new Pointers, then FlatPointers will be set -// to the same array as the super class's. +// It comprises all the Pointers from superclasses plus this class's own +// Pointers. If this class does not define any new Pointers, then +// FlatPointers will be set to the same array as the super class. +// +//========================================================================== + void PClass::BuildFlatPointers () { if (FlatPointers != NULL) @@ -433,6 +928,14 @@ void PClass::BuildFlatPointers () } } +//========================================================================== +// +// PClass :: NativeClass +// +// Finds the underlying native type underlying this class. +// +//========================================================================== + const PClass *PClass::NativeClass() const { const PClass *cls = this; @@ -443,6 +946,12 @@ const PClass *PClass::NativeClass() const return cls; } +//========================================================================== +// +// PClass :: PropagateMark +// +//========================================================================== + size_t PClass::PropagateMark() { size_t marked; @@ -453,6 +962,74 @@ size_t PClass::PropagateMark() return marked + Super::PropagateMark(); } +/* FTypeTable **************************************************************/ + +//========================================================================== +// +// FTypeTable :: FindType +// +//========================================================================== + +PType *FTypeTable::FindType(PClass *metatype, void *parm1, void *parm2, size_t *bucketnum) +{ + size_t bucket = Hash(metatype, parm1, parm2) % HASH_SIZE; + if (bucketnum != NULL) + { + *bucketnum = bucket; + } + for (PType *type = TypeHash[bucket]; type != NULL; type = type->HashNext) + { + if (type->GetClass()->TypeTableType == metatype && type->IsMatch(parm1, parm2)) + { + return type; + } + } + return NULL; +} + +//========================================================================== +// +// FTypeTable :: AddType +// +//========================================================================== + +void FTypeTable::AddType(PType *type, PClass *metatype, void *parm1, void *parm2, size_t bucket) +{ +#ifdef _DEBUG + size_t bucketcheck; + assert(metatype == type->GetClass()->TypeTableType && "Metatype does not match passed object"); + assert(FindType(metatype, parm1, parm2, &bucketcheck) == NULL && "Type must not be inserted more than once"); + assert(bucketcheck == bucket && "Passed bucket was wrong"); +#endif + type->HashNext = TypeHash[bucket]; + TypeHash[bucket] = type; +} + +//========================================================================== +// +// FTypeTable :: Hash STATIC +// +//========================================================================== + +size_t FTypeTable::Hash(void *p1, void *p2, void *p3) +{ + size_t i1 = (size_t)p1; + size_t i2 = (size_t)p2; + size_t i3 = (size_t)p3; + + // Swap the high and low halves of i1. The compiler should be smart enough + // to transform this into a ROR or ROL. + i1 = (i1 >> (sizeof(size_t)*4)) | (i1 << (sizeof(size_t)*4)); + + return (~i1 ^ i2) + i3 * 961748927; // i3 is multiplied by a prime +} + +#include "c_dispatch.h" +CCMD(typetable) +{ + DumpTypeTable(); +} + // Symbol tables ------------------------------------------------------------ IMPLEMENT_ABSTRACT_CLASS(PSymbol); @@ -465,6 +1042,12 @@ IMPLEMENT_POINTY_CLASS(PSymbolVMFunction) DECLARE_POINTER(Function) END_POINTERS +//========================================================================== +// +// +// +//========================================================================== + PSymbol::~PSymbol() { } diff --git a/src/dobjtype.h b/src/dobjtype.h index ac8e64e7e..538e4574e 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -140,28 +140,274 @@ private: friend class DObject; }; +// Basic information shared by all types ------------------------------------ + +// Only one copy of a type is ever instantiated at one time. +// - Enums, classes, and structs are defined by their names and outer classes. +// - Pointers are uniquely defined by the type they point at. +// - ClassPointers are also defined by their class restriction. +// - Arrays are defined by their element type and count. +// - DynArrays are defined by their element type. +// - Maps are defined by their key and value types. +// - Prototypes are defined by the argument and return types. +// - Functions are defined by their names and outer objects. +// In table form: +// Outer Name Type Type2 Count +// Enum * * +// Class * * +// Struct * * +// Function * * +// Pointer * +// ClassPointer + * +// Array * * +// DynArray * +// Map * * +// Prototype *+ *+ + +class PClassType; +class PType : public DObject +{ + //DECLARE_ABSTRACT_CLASS_WITH_META(PType, DObject, PClassType); + // We need to unravel the _WITH_META macro, since PClassType isn't defined yet, + // and we can't define it until we've defined PClass. But we can't define that + // without defining PType. + DECLARE_ABSTRACT_CLASS(PType, DObject) +protected: + enum { MetaClassNum = CLASSREG_PClassType }; +public: + typedef PClassType MetaClass; + MetaClass *GetClass() const; + + unsigned int Size; // this type's size + unsigned int Align; // this type's preferred alignment + PType *HashNext; // next type in this type table + + PType(); + virtual ~PType(); + + // Returns true if this type matches the two identifiers. Referring to the + // above table, any type is identified by at most two characteristics. Each + // type that implements this function will cast these to the appropriate type. + // 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; + + static void StaticInit(); +}; + +// Some categorization typing ----------------------------------------------- + +class PBasicType : public PType +{ + DECLARE_ABSTRACT_CLASS(PBasicType, PType); +}; + +class PCompoundType : public PType +{ + DECLARE_ABSTRACT_CLASS(PCompoundType, PType); +}; + +class PNamedType : public PCompoundType +{ + DECLARE_ABSTRACT_CLASS(PNamedType, PCompoundType); + HAS_OBJECT_POINTERS; +public: + DObject *Outer; // object this type is contained within + FName TypeName; // this type's name + + PNamedType() : Outer(NULL) {} + + virtual bool IsMatch(const void *id1, const void *id2) const; +}; + +// Basic types -------------------------------------------------------------- + +class PInt : public PBasicType +{ + DECLARE_CLASS(PInt, PBasicType); +}; + +class PFloat : public PBasicType +{ + DECLARE_CLASS(PFloat, PBasicType); +}; + +class PString : public PBasicType +{ + DECLARE_CLASS(PString, PBasicType); +}; + +// Variations of integer types ---------------------------------------------- + +class PName : public PInt +{ + DECLARE_CLASS(PName, PInt); +}; + +class PSound : public PInt +{ + DECLARE_CLASS(PSound, PInt); +}; + +class PColor : public PInt +{ + DECLARE_CLASS(PColor, PInt); +}; + +// Pointers ----------------------------------------------------------------- + +class PPointer : public PInt +{ + DECLARE_CLASS(PPointer, PInt); + HAS_OBJECT_POINTERS; +public: + PType *PointedType; + + virtual bool IsMatch(const void *id1, const void *id2) const; +}; + +class PClass; +class PClassPointer : public PPointer +{ + DECLARE_CLASS(PClassPointer, PPointer); + HAS_OBJECT_POINTERS; +public: + PClass *ClassRestriction; + + typedef PClass *Type2; + + virtual bool IsMatch(const void *id1, const void *id2) const; +}; + +// Struct/class fields ------------------------------------------------------ + +class PField : public DObject +{ + DECLARE_ABSTRACT_CLASS(PField, DObject); +public: + FName FieldName; +}; + +class PMemberField : public PField +{ + DECLARE_CLASS(PMemberField, PField); + HAS_OBJECT_POINTERS +public: + unsigned int FieldOffset; + PType *FieldType; +}; + +// Compound types ----------------------------------------------------------- + +class PEnum : public PNamedType +{ + DECLARE_CLASS(PEnum, PNamedType); + HAS_OBJECT_POINTERS; +public: + PType *ValueType; + TMap<FName, int> Values; +}; + +class PArray : public PCompoundType +{ + DECLARE_CLASS(PArray, PCompoundType); + HAS_OBJECT_POINTERS; +public: + PType *ElementType; + unsigned int ElementCount; + + virtual bool IsMatch(const void *id1, const void *id2) const; +}; + +// A vector is an array with extra operations. +class PVector : public PArray +{ + DECLARE_CLASS(PVector, PArray); + HAS_OBJECT_POINTERS; +}; + +class PDynArray : public PCompoundType +{ + DECLARE_CLASS(PDynArray, PCompoundType); + HAS_OBJECT_POINTERS; +public: + PType *ElementType; + + virtual bool IsMatch(const void *id1, const void *id2) const; +}; + +class PMap : public PCompoundType +{ + DECLARE_CLASS(PMap, PCompoundType); + HAS_OBJECT_POINTERS; +public: + PType *KeyType; + PType *ValueType; + + virtual bool IsMatch(const void *id1, const void *id2) const; +}; + +class PStruct : public PNamedType +{ + DECLARE_CLASS(PStruct, PNamedType); +public: + TArray<PField *> Fields; + + size_t PropagateMark(); +}; + +class PPrototype : public PCompoundType +{ + DECLARE_CLASS(PPrototype, PCompoundType); +public: + TArray<PType *> ArgumentTypes; + TArray<PType *> ReturnTypes; + + size_t PropagateMark(); + virtual bool IsMatch(const void *id1, const void *id2) const; +}; + +// TBD: Should we support overloading? +class PFunction : public PNamedType +{ + DECLARE_CLASS(PFunction, PNamedType); +public: + struct Variant + { + PPrototype *Proto; + VMFunction *Implementation; + }; + TArray<Variant> Variants; + + size_t PropagateMark(); +}; + // Meta-info for every class derived from DObject --------------------------- -class PClass : public DObject +class PClassClass; +class PClass : public PStruct { - DECLARE_CLASS(PClass, DObject); + DECLARE_CLASS(PClass, PStruct); HAS_OBJECT_POINTERS; protected: virtual void Derive(PClass *newclass); + // We unravel _WITH_META here just as we did for PType. + enum { MetaClassNum = CLASSREG_PClassClass }; public: - static void StaticInit (); - static void StaticShutdown (); + typedef PClassClass MetaClass; + MetaClass *GetClass() const; + + static void StaticInit(); + static void StaticShutdown(); + static void StaticBootstrap(); // Per-class information ------------------------------------- - FName TypeName; // this class's name - unsigned int Size; // this class's size PClass *ParentClass; // the class this class derives from const size_t *Pointers; // object pointers defined by this class *only* const size_t *FlatPointers; // object pointers defined by this class and all its superclasses; not initialized by default - PClass *HashNext; BYTE *Defaults; bool bRuntimeClass; // class was defined at run-time, not compile-time - unsigned short ClassIndex; PSymbolTable Symbols; void (*ConstructNative)(void *); @@ -169,17 +415,17 @@ public: // The rest are all functions and static data ---------------- PClass(); ~PClass(); - void InsertIntoHash (); - DObject *CreateNew () const; - PClass *CreateDerivedClass (FName name, unsigned int size); + void InsertIntoHash(); + DObject *CreateNew() const; + PClass *CreateDerivedClass(FName name, unsigned int size); unsigned int Extend(unsigned int extension); - void InitializeActorInfo (); - void BuildFlatPointers (); + void InitializeActorInfo(); + void BuildFlatPointers(); const PClass *NativeClass() const; size_t PropagateMark(); // Returns true if this type is an ancestor of (or same as) the passed type. - bool IsAncestorOf (const PClass *ti) const + bool IsAncestorOf(const PClass *ti) const { while (ti) { @@ -189,29 +435,70 @@ public: } return false; } - inline bool IsDescendantOf (const PClass *ti) const + inline bool IsDescendantOf(const PClass *ti) const { - return ti->IsAncestorOf (this); + return ti->IsAncestorOf(this); } // Find a type, given its name. - static PClass *FindClass (const char *name) { return FindClass (FName (name, true)); } - static PClass *FindClass (const FString &name) { return FindClass (FName (name, true)); } - static PClass *FindClass (ENamedName name) { return FindClass (FName (name)); } - static PClass *FindClass (FName name); - static PClassActor *FindActor (const char *name) { return FindActor (FName (name, true)); } - static PClassActor *FindActor (const FString &name) { return FindActor (FName (name, true)); } - static PClassActor *FindActor (ENamedName name) { return FindActor (FName (name)); } - static PClassActor *FindActor (FName name); - PClass *FindClassTentative (FName name); // not static! + static PClass *FindClass(const char *name) { return FindClass(FName(name, true)); } + static PClass *FindClass(const FString &name) { return FindClass(FName(name, true)); } + static PClass *FindClass(ENamedName name) { return FindClass(FName(name)); } + static PClass *FindClass(FName name); + static PClassActor *FindActor(const char *name) { return FindActor(FName(name, true)); } + static PClassActor *FindActor(const FString &name) { return FindActor(FName(name, true)); } + static PClassActor *FindActor(ENamedName name) { return FindActor(FName(name)); } + static PClassActor *FindActor(FName name); + PClass *FindClassTentative(FName name); // not static! - static TArray<PClass *> m_Types; - static TArray<PClassActor *> m_RuntimeActors; - - enum { HASH_SIZE = 256 }; - static PClass *TypeHash[HASH_SIZE]; + static TArray<PClass *> AllClasses; static bool bShutdown; }; +class PClassType : public PClass +{ + DECLARE_CLASS(PClassType, PClass); +protected: + virtual void Derive(PClass *newclass); +public: + PClassType(); + + PClass *TypeTableType; // The type to use for hashing into the type table +}; + +inline PType::MetaClass *PType::GetClass() const +{ + return static_cast<MetaClass *>(DObject::GetClass()); +} + +class PClassClass : public PClassType +{ + DECLARE_CLASS(PClassClass, PClassType); +public: + PClassClass(); +}; + +inline PClass::MetaClass *PClass::GetClass() const +{ + return static_cast<MetaClass *>(DObject::GetClass()); +} + +// Type tables -------------------------------------------------------------- + +struct FTypeTable +{ + enum { HASH_SIZE = 1021 }; + + PType *TypeHash[HASH_SIZE]; + + PType *FindType(PClass *metatype, void *parm1, void *parm2, size_t *bucketnum); + void AddType(PType *type, PClass *metatype, void *parm1, void *parm2, size_t bucket); + + static size_t Hash(void *p1, void *p2, void *p3); +}; + + +extern FTypeTable TypeTable; + #endif diff --git a/src/farchive.cpp b/src/farchive.cpp index 3920479e7..694736583 100644 --- a/src/farchive.cpp +++ b/src/farchive.cpp @@ -637,12 +637,8 @@ FArchive::FArchive (FFile &file) void FArchive::AttachToFile (FFile &file) { - unsigned int i; - m_HubTravel = false; m_File = &file; - m_MaxObjectCount = m_ObjectCount = 0; - m_ObjectMap = NULL; if (file.Mode() == FFile::EReading) { m_Loading = true; @@ -654,19 +650,13 @@ void FArchive::AttachToFile (FFile &file) m_Storing = true; } m_Persistent = file.IsPersistent(); - m_TypeMap = NULL; - m_TypeMap = new TypeMap[PClass::m_Types.Size()]; - for (i = 0; i < PClass::m_Types.Size(); i++) - { - m_TypeMap[i].toArchive = TypeMap::NO_INDEX; - m_TypeMap[i].toCurrent = NULL; - } - m_ClassCount = 0; - for (i = 0; i < EObjectHashSize; i++) - { - m_ObjectHash[i] = ~0; - m_NameHash[i] = NameMap::NO_INDEX; - } + + ClassToArchive.Clear(); + ArchiveToClass.Clear(); + + ObjectToArchive.Clear(); + ArchiveToObject.Clear(); + m_NumSprites = 0; m_SpriteMap = new int[sprites.Size()]; for (size_t s = 0; s < sprites.Size(); ++s) @@ -678,10 +668,6 @@ void FArchive::AttachToFile (FFile &file) FArchive::~FArchive () { Close (); - if (m_TypeMap) - delete[] m_TypeMap; - if (m_ObjectMap) - M_Free (m_ObjectMap); if (m_SpriteMap) delete[] m_SpriteMap; } @@ -702,7 +688,7 @@ void FArchive::Close () { m_File->Close (); m_File = NULL; - DPrintf ("Processed %u objects\n", m_ObjectCount); + DPrintf ("Processed %u objects\n", ArchiveToObject.Size()); } } @@ -1044,6 +1030,7 @@ FArchive &FArchive::WriteObject (DObject *obj) else { PClass *type = obj->GetClass(); + DWORD *classarcid; if (type == RUNTIME_CLASS(DObject)) { @@ -1052,7 +1039,7 @@ FArchive &FArchive::WriteObject (DObject *obj) id[0] = NULL_OBJ; Write (id, 1); } - else if (m_TypeMap[type->ClassIndex].toArchive == TypeMap::NO_INDEX) + else if (NULL == (classarcid = ClassToArchive.CheckKey(type))) { // No instances of this class have been written out yet. // Write out the class, then write out the object. If this @@ -1085,9 +1072,9 @@ FArchive &FArchive::WriteObject (DObject *obj) // to the saved object. Otherwise, save a reference to the // class, then save the object. Again, if this is a player- // controlled actor, remember that. - DWORD index = FindObjectIndex (obj); + DWORD *objarcid = ObjectToArchive.CheckKey(obj); - if (index == TypeMap::NO_INDEX) + if (objarcid == NULL) { if (obj->IsKindOf (RUNTIME_CLASS (AActor)) && @@ -1103,7 +1090,7 @@ FArchive &FArchive::WriteObject (DObject *obj) id[0] = NEW_OBJ; Write (id, 1); } - WriteCount (m_TypeMap[type->ClassIndex].toArchive); + WriteCount (*classarcid); // Printf ("Reuse class %s (%u)\n", type->Name, m_File->Tell()); MapObject (obj); obj->SerializeUserVars (*this); @@ -1114,7 +1101,7 @@ FArchive &FArchive::WriteObject (DObject *obj) { id[0] = OLD_OBJ; Write (id, 1); - WriteCount (index); + WriteCount (*objarcid); } } } @@ -1141,12 +1128,12 @@ FArchive &FArchive::ReadObject (DObject* &obj, PClass *wanttype) break; case OLD_OBJ: - index = ReadCount (); - if (index >= m_ObjectCount) + index = ReadCount(); + if (index >= ArchiveToObject.Size()) { - I_Error ("Object reference too high (%u; max is %u)\n", index, m_ObjectCount); + I_Error ("Object reference too high (%u; max is %u)\n", index, ArchiveToObject.Size()); } - obj = (DObject *)m_ObjectMap[index].object; + obj = ArchiveToObject[index]; break; case NEW_PLYR_CLS_OBJ: @@ -1363,19 +1350,14 @@ DWORD FArchive::FindName (const char *name, unsigned int bucket) const DWORD FArchive::WriteClass (PClass *info) { - if (m_ClassCount >= PClass::m_Types.Size()) - { - I_Error ("Too many unique classes have been written.\nOnly %u were registered\n", - PClass::m_Types.Size()); - } - if (m_TypeMap[info->ClassIndex].toArchive != TypeMap::NO_INDEX) + if (ClassToArchive.CheckKey(info) != NULL) { I_Error ("Attempt to write '%s' twice.\n", info->TypeName.GetChars()); } - m_TypeMap[info->ClassIndex].toArchive = m_ClassCount; - m_TypeMap[m_ClassCount].toCurrent = info; + DWORD index = ArchiveToClass.Push(info); + ClassToArchive[info] = index; WriteString (info->TypeName.GetChars()); - return m_ClassCount++; + return index; } PClass *FArchive::ReadClass () @@ -1386,24 +1368,15 @@ PClass *FArchive::ReadClass () char *val; } typeName; - if (m_ClassCount >= PClass::m_Types.Size()) - { - I_Error ("Too many unique classes have been read.\nOnly %u were registered\n", - PClass::m_Types.Size()); - } operator<< (typeName.val); FName zaname(typeName.val, true); if (zaname != NAME_None) { - for (unsigned int i = PClass::m_Types.Size(); i-- > 0; ) + PClass *type = PClass::FindClass(zaname); + if (type != NULL) { - if (PClass::m_Types[i]->TypeName == zaname) - { - m_TypeMap[i].toArchive = m_ClassCount; - m_TypeMap[m_ClassCount].toCurrent = PClass::m_Types[i]; - m_ClassCount++; - return PClass::m_Types[i]; - } + ClassToArchive[type] = ArchiveToClass.Push(type); + return type; } } I_Error ("Unknown class '%s'\n", typeName.val); @@ -1425,11 +1398,7 @@ PClass *FArchive::ReadClass (const PClass *wanttype) PClass *FArchive::ReadStoredClass (const PClass *wanttype) { DWORD index = ReadCount (); - if (index >= m_ClassCount) - { - I_Error ("Class reference too high (%u; max is %u)\n", index, m_ClassCount); - } - PClass *type = m_TypeMap[index].toCurrent; + PClass *type = ArchiveToClass[index]; if (!type->IsDescendantOf (wanttype)) { I_Error ("Expected to extract an object of type '%s'.\n" @@ -1439,44 +1408,11 @@ PClass *FArchive::ReadStoredClass (const PClass *wanttype) return type; } -DWORD FArchive::MapObject (const DObject *obj) +DWORD FArchive::MapObject (DObject *obj) { - DWORD i; - - if (m_ObjectCount >= m_MaxObjectCount) - { - m_MaxObjectCount = m_MaxObjectCount ? m_MaxObjectCount * 2 : 1024; - m_ObjectMap = (ObjectMap *)M_Realloc (m_ObjectMap, sizeof(ObjectMap)*m_MaxObjectCount); - for (i = m_ObjectCount; i < m_MaxObjectCount; i++) - { - m_ObjectMap[i].hashNext = ~0; - m_ObjectMap[i].object = NULL; - } - } - - DWORD index = m_ObjectCount++; - DWORD hash = HashObject (obj); - - m_ObjectMap[index].object = obj; - m_ObjectMap[index].hashNext = m_ObjectHash[hash]; - m_ObjectHash[hash] = index; - - return index; -} - -DWORD FArchive::HashObject (const DObject *obj) const -{ - return (DWORD)((size_t)obj % EObjectHashSize); -} - -DWORD FArchive::FindObjectIndex (const DObject *obj) const -{ - DWORD index = m_ObjectHash[HashObject (obj)]; - while (index != TypeMap::NO_INDEX && m_ObjectMap[index].object != obj) - { - index = m_ObjectMap[index].hashNext; - } - return index; + DWORD i = ArchiveToObject.Push(obj); + ObjectToArchive[obj] = i; + return i; } void FArchive::UserWriteClass (PClass *type) @@ -1490,7 +1426,8 @@ void FArchive::UserWriteClass (PClass *type) } else { - if (m_TypeMap[type->ClassIndex].toArchive == TypeMap::NO_INDEX) + DWORD *arcid; + if (NULL == (arcid = ClassToArchive.CheckKey(type))) { id = 1; Write (&id, 1); @@ -1500,7 +1437,7 @@ void FArchive::UserWriteClass (PClass *type) { id = 0; Write (&id, 1); - WriteCount (m_TypeMap[type->ClassIndex].toArchive); + WriteCount (*arcid); } } } diff --git a/src/farchive.h b/src/farchive.h index e994e6d56..32e3b4b6f 100644 --- a/src/farchive.h +++ b/src/farchive.h @@ -209,13 +209,11 @@ inline FArchive& operator<< (DObject* &object) { return ReadObject (object, RUN protected: enum { EObjectHashSize = 137 }; - DWORD FindObjectIndex (const DObject *obj) const; - DWORD MapObject (const DObject *obj); + DWORD MapObject (DObject *obj); DWORD WriteClass (PClass *info); PClass *ReadClass (); PClass *ReadClass (const PClass *wanttype); PClass *ReadStoredClass (const PClass *wanttype); - DWORD HashObject (const DObject *obj) const; DWORD AddName (const char *name); DWORD AddName (unsigned int start); // Name has already been added to storage DWORD FindName (const char *name) const; @@ -226,24 +224,12 @@ protected: bool m_Storing; // inserting objects? bool m_HubTravel; // travelling inside a hub? FFile *m_File; // unerlying file object - DWORD m_ObjectCount; // # of objects currently serialized - DWORD m_MaxObjectCount; - DWORD m_ClassCount; // # of unique classes currently serialized - struct TypeMap - { - PClass *toCurrent; // maps archive type index to execution type index - DWORD toArchive; // maps execution type index to archive type index + TMap<PClass *, DWORD> ClassToArchive; // Maps PClass to archive type index + TArray<PClass *> ArchiveToClass; // Maps archive type index to PClass - enum { NO_INDEX = 0xffffffff }; - } *m_TypeMap; - - struct ObjectMap - { - const DObject *object; - DWORD hashNext; - } *m_ObjectMap; - DWORD m_ObjectHash[EObjectHashSize]; + TMap<DObject *, DWORD> ObjectToArchive; // Maps objects to archive index + TArray<DObject *> ArchiveToObject; // Maps archive index to objects struct NameMap { diff --git a/src/g_shared/a_keys.cpp b/src/g_shared/a_keys.cpp index 064f1e1ec..2a2bdca06 100644 --- a/src/g_shared/a_keys.cpp +++ b/src/g_shared/a_keys.cpp @@ -309,27 +309,27 @@ static void ParseLock(FScanner &sc) static void ClearLocks() { unsigned int i; - for(i=0;i<PClass::m_Types.Size();i++) + for(i = 0; i < PClassActor::AllActorClasses.Size(); i++) { - if (PClass::m_Types[i]->IsDescendantOf(RUNTIME_CLASS(AKey))) + if (PClassActor::AllActorClasses[i]->IsDescendantOf(RUNTIME_CLASS(AKey))) { - AKey *key = static_cast<AKey*>(GetDefaultByType(PClass::m_Types[i])); + AKey *key = static_cast<AKey*>(GetDefaultByType(PClassActor::AllActorClasses[i])); if (key != NULL) { key->KeyNumber = 0; } } } - for(i=0;i<256;i++) + for(i = 0; i < 256; i++) { - if (locks[i]!=NULL) + if (locks[i] != NULL) { delete locks[i]; - locks[i]=NULL; + locks[i] = NULL; } } - currentnumber=0; - keysdone=false; + currentnumber = 0; + keysdone = false; } //=========================================================================== diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index f877de77b..e4842b3ad 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -1643,9 +1643,9 @@ AInventory *ABackpackItem::CreateCopy (AActor *other) { // Find every unique type of ammo. Give it to the player if // he doesn't have it already, and double its maximum capacity. - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClass *type = PClass::m_Types[i]; + PClass *type = PClassActor::AllActorClasses[i]; if (type->ParentClass == RUNTIME_CLASS(AAmmo)) { diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index 97b438853..326b82323 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -1119,9 +1119,9 @@ void FWeaponSlots::AddExtraWeapons() } // Append extra weapons to the slots. - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClass *cls = PClass::m_Types[i]; + PClass *cls = PClassActor::AllActorClasses[i]; if (!cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { @@ -1569,9 +1569,9 @@ void P_SetupWeapons_ntohton() cls = NULL; Weapons_ntoh.Push(cls); // Index 0 is always NULL. - for (i = 0; i < PClass::m_Types.Size(); ++i) + for (i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClass *cls = PClass::m_Types[i]; + PClassActor *cls = PClassActor::AllActorClasses[i]; if (cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index 08086e62c..61c44cc27 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -2161,7 +2161,7 @@ class CommandPlayerClass : public SBarInfoCommandFlowControl if(statusBar->CPlayer->cls == NULL) return; //No class so we can not continue - int spawnClass = statusBar->CPlayer->cls->ClassIndex; + PClass *spawnClass = statusBar->CPlayer->cls; for(unsigned int i = 0;i < classes.Size();i++) { if(classes[i] == spawnClass) @@ -2179,7 +2179,7 @@ class CommandPlayerClass : public SBarInfoCommandFlowControl if(stricmp(sc.String, PlayerClasses[c].Type->DisplayName) == 0) { foundClass = true; - classes.Push(PlayerClasses[c].Type->ClassIndex); + classes.Push(PlayerClasses[c].Type); break; } } @@ -2192,7 +2192,7 @@ class CommandPlayerClass : public SBarInfoCommandFlowControl SBarInfoCommandFlowControl::Parse(sc, fullScreenOffsets); } protected: - TArray<int> classes; + TArray<PClass*> classes; }; //////////////////////////////////////////////////////////////////////////////// diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index a8d570605..8ab2fd3aa 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -327,9 +327,9 @@ static int STACK_ARGS ktcmp(const void * a, const void * b) static void SetKeyTypes() { - for(unsigned int i = 0; i < PClass::m_Types.Size(); i++) + for(unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); i++) { - PClass *ti = PClass::m_Types[i]; + PClass *ti = PClassActor::AllActorClasses[i]; if (ti->IsDescendantOf(RUNTIME_CLASS(AKey))) { diff --git a/src/info.cpp b/src/info.cpp index 5804a7857..1b67189cf 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -53,6 +53,8 @@ extern void LoadActors (); +TArray<PClassActor *> PClassActor::AllActorClasses; + bool FState::CallAction(AActor *self, AActor *stateowner, StateCallData *statecall) { if (ActionFunc != NULL) @@ -151,9 +153,9 @@ void PClassActor::StaticSetActorNums() memset(SpawnableThings, 0, sizeof(SpawnableThings)); DoomEdMap.Empty(); - for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - static_cast<PClassActor *>(PClass::m_RuntimeActors[i])->RegisterIDs(); + static_cast<PClassActor *>(PClassActor::AllActorClasses[i])->RegisterIDs(); } } @@ -195,6 +197,9 @@ PClassActor::PClassActor() ExplosionRadius = -1; MissileHeight = 32*FRACUNIT; MeleeDamage = 0; + + // Record this in the master list. + AllActorClasses.Push(this); } //========================================================================== @@ -308,7 +313,6 @@ void PClassActor::InitializeNativeDefaults() { memset (Defaults, 0, Size); } - m_RuntimeActors.Push(this); } //========================================================================== @@ -585,7 +589,7 @@ static int STACK_ARGS sortnums (const void *a, const void *b) void FDoomEdMap::DumpMapThings () { - TArray<EdSorting> infos (PClass::m_Types.Size()); + TArray<EdSorting> infos (PClassActor::AllActorClasses.Size()); int i; for (i = 0; i < DOOMED_HASHSIZE; ++i) diff --git a/src/info.h b/src/info.h index a6f37771c..54ff8eb63 100644 --- a/src/info.h +++ b/src/info.h @@ -194,6 +194,9 @@ public: FSoundID MeleeSound; FName MissileName; fixed_t MissileHeight; + + // For those times when being able to scan every kind of actor is convenient + static TArray<PClassActor *> AllActorClasses; }; inline PClassActor *PClass::FindActor(FName name) diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 8a04be64e..64f2c4535 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -603,7 +603,7 @@ void cht_Give (player_t *player, const char *name, int amount) { bool giveall; int i; - PClass *type; + PClassActor *type; if (player != &players[consoleplayer]) Printf ("%s is a cheater: give %s\n", player->userinfo.netname, name); @@ -648,7 +648,7 @@ void cht_Give (player_t *player, const char *name, int amount) if (giveall || stricmp (name, "backpack") == 0) { // Select the correct type of backpack based on the game - type = PClass::FindClass(gameinfo.backpacktype); + type = PClass::FindActor(gameinfo.backpacktype); if (type != NULL) { GiveSpawner (player, static_cast<PClassInventory *>(type), 1); @@ -662,9 +662,9 @@ void cht_Give (player_t *player, const char *name, int amount) { // Find every unique type of ammo. Give it to the player if // he doesn't have it already, and set each to its maximum. - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClass *type = PClass::m_Types[i]; + PClassActor *type = PClassActor::AllActorClasses[i]; if (type->ParentClass == RUNTIME_CLASS(AAmmo)) { @@ -719,14 +719,14 @@ void cht_Give (player_t *player, const char *name, int amount) if (giveall || stricmp (name, "keys") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - if (PClass::m_Types[i]->IsDescendantOf (RUNTIME_CLASS(AKey))) + if (PClassActor::AllActorClasses[i]->IsDescendantOf (RUNTIME_CLASS(AKey))) { - AKey *key = (AKey *)GetDefaultByType (PClass::m_Types[i]); + AKey *key = (AKey *)GetDefaultByType (PClassActor::AllActorClasses[i]); if (key->KeyNumber != 0) { - key = static_cast<AKey *>(Spawn(static_cast<PClassActor *>(PClass::m_Types[i]), 0,0,0, NO_REPLACE)); + key = static_cast<AKey *>(Spawn(static_cast<PClassActor *>(PClassActor::AllActorClasses[i]), 0,0,0, NO_REPLACE)); if (!key->CallTryPickup (player->mo)) { key->Destroy (); @@ -741,9 +741,9 @@ void cht_Give (player_t *player, const char *name, int amount) if (giveall || stricmp (name, "weapons") == 0) { AWeapon *savedpending = player->PendingWeapon; - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - type = PClass::m_Types[i]; + type = PClassActor::AllActorClasses[i]; // Don't give replaced weapons unless the replacement was done by Dehacked. if (type != RUNTIME_CLASS(AWeapon) && type->IsDescendantOf (RUNTIME_CLASS(AWeapon)) && @@ -772,9 +772,9 @@ void cht_Give (player_t *player, const char *name, int amount) if (giveall || stricmp (name, "artifacts") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - type = PClass::m_Types[i]; + type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS(AInventory))) { AInventory *def = (AInventory*)GetDefaultByType (type); @@ -793,9 +793,9 @@ void cht_Give (player_t *player, const char *name, int amount) if (giveall || stricmp (name, "puzzlepieces") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - type = PClass::m_Types[i]; + type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS(APuzzleItem))) { AInventory *def = (AInventory*)GetDefaultByType (type); @@ -812,7 +812,7 @@ void cht_Give (player_t *player, const char *name, int amount) if (giveall) return; - type = PClass::FindClass (name); + type = PClass::FindActor(name); if (type == NULL || !type->IsDescendantOf (RUNTIME_CLASS(AInventory))) { if (player == &players[consoleplayer]) @@ -872,9 +872,9 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall || stricmp (name, "backpack") == 0) { // Take away all types of backpacks the player might own. - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClass *type = PClass::m_Types[i]; + PClass *type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf(RUNTIME_CLASS (ABackpackItem))) { @@ -891,9 +891,9 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall || stricmp (name, "ammo") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClass *type = PClass::m_Types[i]; + PClass *type = PClassActor::AllActorClasses[i]; if (type->ParentClass == RUNTIME_CLASS (AAmmo)) { @@ -910,9 +910,9 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall || stricmp (name, "armor") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - type = PClass::m_Types[i]; + type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (AArmor))) { @@ -929,9 +929,9 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall || stricmp (name, "keys") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - type = PClass::m_Types[i]; + type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (AKey))) { @@ -948,9 +948,9 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall || stricmp (name, "weapons") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - type = PClass::m_Types[i]; + type = PClassActor::AllActorClasses[i]; if (type != RUNTIME_CLASS(AWeapon) && type->IsDescendantOf (RUNTIME_CLASS (AWeapon))) @@ -973,9 +973,9 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall || stricmp (name, "artifacts") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - type = PClass::m_Types[i]; + type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (AInventory))) { @@ -999,9 +999,9 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall || stricmp (name, "puzzlepieces") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - type = PClass::m_Types[i]; + type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (APuzzleItem))) { diff --git a/src/namedef.h b/src/namedef.h index a95b4b5a0..56c80ff08 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -5,6 +5,8 @@ xx(Null) xx(Super) xx(Object) xx(Actor) +xx(Class) +xx(ClassClass) xx(Untranslated) diff --git a/src/p_states.cpp b/src/p_states.cpp index 25fd73f70..ecbb3d05f 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -119,9 +119,9 @@ FArchive &operator<< (FArchive &arc, FState *&state) PClassActor *FState::StaticFindStateOwner (const FState *state) { - for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClassActor *info = PClass::m_RuntimeActors[i]; + PClassActor *info = PClassActor::AllActorClasses[i]; if (state >= info->OwnedStates && state < info->OwnedStates + info->NumOwnedStates) { @@ -966,9 +966,9 @@ void DumpStateHelper(FStateLabels *StateList, const FString &prefix) CCMD(dumpstates) { - for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClassActor *info = PClass::m_RuntimeActors[i]; + PClassActor *info = PClassActor::AllActorClasses[i]; Printf(PRINT_LOG, "State labels for %s\n", info->TypeName.GetChars()); DumpStateHelper(info->StateList, ""); Printf(PRINT_LOG, "----------------------------\n"); diff --git a/src/p_user.cpp b/src/p_user.cpp index b3973a8fa..acaaf28a9 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -810,14 +810,14 @@ void APlayerPawn::CheckWeaponSwitch(const PClass *ammotype) void APlayerPawn::GiveDeathmatchInventory() { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - if (PClass::m_Types[i]->IsDescendantOf (RUNTIME_CLASS(AKey))) + if (PClassActor::AllActorClasses[i]->IsDescendantOf (RUNTIME_CLASS(AKey))) { - AKey *key = (AKey *)GetDefaultByType (PClass::m_Types[i]); + AKey *key = (AKey *)GetDefaultByType (PClassActor::AllActorClasses[i]); if (key->KeyNumber != 0) { - key = static_cast<AKey *>(Spawn(static_cast<PClassActor *>(PClass::m_Types[i]), 0,0,0, NO_REPLACE)); + key = static_cast<AKey *>(Spawn(static_cast<PClassActor *>(PClassActor::AllActorClasses[i]), 0,0,0, NO_REPLACE)); if (!key->CallTryPickup (this)) { key->Destroy (); diff --git a/src/tarray.h b/src/tarray.h index b325a640b..cced36e4b 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -119,6 +119,22 @@ public: Most = 0; } } + // Check equality of two arrays + bool operator==(const TArray<T> &other) const + { + if (Count != other.Count) + { + return false; + } + for (unsigned int i = 0; i < Count; ++i) + { + if (Array[i] != other.Array[i]) + { + return false; + } + } + return true; + } // Return a reference to an element T &operator[] (size_t index) const { diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 4cc1b9bf7..08ca849b2 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -119,6 +119,8 @@ PClassActor *CreateNewActor(const FScriptPosition &sc, FName typeName, FName par ti = PClass::FindActor(typeName); if (ti == NULL) { + extern void DumpTypeTable(); + DumpTypeTable(); sc.Message(MSG_ERROR, "Unknown native actor '%s'", typeName.GetChars()); goto create; } @@ -319,12 +321,9 @@ static void FinishThingdef() } fclose(dump); - for (i = 0; i < PClass::m_Types.Size(); i++) + for (i = 0; i < PClassActor::AllActorClasses.Size(); i++) { - PClass * ti = PClass::m_Types[i]; - - // Skip non-actors - if (!ti->IsDescendantOf(RUNTIME_CLASS(AActor))) continue; + PClassActor *ti = PClassActor::AllActorClasses[i]; if (ti->Size == (unsigned)-1) { diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 9ff623a5e..734e3e12b 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -2490,7 +2490,7 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build) sym = symfunc; RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); } - assert(sym->SymbolType == SYM_VMFunction); + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; @@ -2595,7 +2595,7 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) sym = symfunc; RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); } - assert(sym->SymbolType == SYM_VMFunction); + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; @@ -2685,7 +2685,7 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) sym = symfunc; RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); } - assert(sym->SymbolType == SYM_VMFunction); + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; @@ -3503,7 +3503,7 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) sym = symfunc; RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); } - assert(sym->SymbolType == SYM_VMFunction); + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; @@ -3763,7 +3763,7 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build) sym = symfunc; RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); } - assert(sym->SymbolType == SYM_VMFunction); + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; @@ -3963,7 +3963,7 @@ ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build) sym = symfunc; RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); } - assert(sym->SymbolType == SYM_VMFunction); + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; From dde5e1928fdbb4bed6949ec8fa9a1ed151a080bb Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Thu, 22 Apr 2010 04:12:42 +0000 Subject: [PATCH 036/232] - Make TypeTable a GC root. - Instantiate some basic types. SVN r2298 (scripting) --- src/dobjgc.cpp | 7 +- src/dobjtype.cpp | 311 +++++++++++++++++++++++++++++++++++++++++++++-- src/dobjtype.h | 43 ++++++- 3 files changed, 345 insertions(+), 16 deletions(-) diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index 105ec1096..1a5f3a557 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -356,11 +356,8 @@ static void MarkRoot() Mark(*(afunc->VMPointer)); } } - // Mark classes - for (unsigned j = 0; j < PClass::AllClasses.Size(); ++j) - { - Mark(PClass::AllClasses[j]); - } + // Mark types + TypeTable.Mark(); // Mark bot stuff. Mark(bglobal.firstthing); Mark(bglobal.body1); diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index a211c55da..d3aa01ce6 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -61,6 +61,16 @@ FTypeTable TypeTable; TArray<PClass *> PClass::AllClasses; bool PClass::bShutdown; +PInt *TypeSInt8, *TypeUInt8; +PInt *TypeSInt16, *TypeUInt16; +PInt *TypeSInt32, *TypeUInt32; +PFloat *TypeFloat32, *TypeFloat64; +PString *TypeString; +PName *TypeName; +PSound *TypeSound; +PColor *TypeColor; + + // PRIVATE DATA DEFINITIONS ------------------------------------------------ // A harmless non-NULL FlatPointer for classes without pointers. @@ -159,11 +169,13 @@ PClassClass::PClassClass() /* PType ******************************************************************/ -IMPLEMENT_ABSTRACT_CLASS(PType) +IMPLEMENT_ABSTRACT_POINTY_CLASS(PType) + DECLARE_POINTER(HashNext) +END_POINTERS //========================================================================== // -// PType Constructor +// PType Default Constructor // //========================================================================== @@ -172,6 +184,17 @@ PType::PType() { } +//========================================================================== +// +// PType Parameterized Constructor +// +//========================================================================== + +PType::PType(unsigned int size, unsigned int align) +: Size(size), Align(align), HashNext(NULL) +{ +} + //========================================================================== // // PType Destructor @@ -193,11 +216,23 @@ bool PType::IsMatch(const void *id1, const void *id2) const return false; } +//========================================================================== +// +// PType :: GetTypeIDs +// +//========================================================================== + +void PType::GetTypeIDs(const void *&id1, const void *&id2) const +{ + id1 = NULL; + id2 = NULL; +} + //========================================================================== // // PType :: StaticInit STATIC // -// Set up TypeTableType values for every PType child. +// Set up TypeTableType values for every PType child and create basic types. // //========================================================================== @@ -220,6 +255,20 @@ void PType::StaticInit() RUNTIME_CLASS(PPrototype)->TypeTableType = RUNTIME_CLASS(PPrototype); RUNTIME_CLASS(PFunction)->TypeTableType = RUNTIME_CLASS(PFunction); RUNTIME_CLASS(PClass)->TypeTableType = RUNTIME_CLASS(PClass); + + TypeTable.AddType(TypeSInt8 = new PInt(1, false)); + TypeTable.AddType(TypeUInt8 = new PInt(1, true)); + TypeTable.AddType(TypeSInt16 = new PInt(2, false)); + TypeTable.AddType(TypeUInt16 = new PInt(2, true)); + TypeTable.AddType(TypeSInt32 = new PInt(4, false)); + TypeTable.AddType(TypeUInt32 = new PInt(4, true)); + TypeTable.AddType(TypeFloat32 = new PFloat(4)); + TypeTable.AddType(TypeFloat64 = new PFloat(8)); + TypeTable.AddType(TypeString = new PString); + TypeTable.AddType(TypeName = new PName); + TypeTable.AddType(TypeSound = new PSound); + TypeTable.AddType(TypeColor = new PColor); + } @@ -227,6 +276,27 @@ void PType::StaticInit() IMPLEMENT_ABSTRACT_CLASS(PBasicType) +//========================================================================== +// +// PBasicType Default Constructor +// +//========================================================================== + +PBasicType::PBasicType() +{ +} + +//========================================================================== +// +// PBasicType Parameterized Constructor +// +//========================================================================== + +PBasicType::PBasicType(unsigned int size, unsigned int align) +: PType(size, align) +{ +} + /* PCompoundType **********************************************************/ IMPLEMENT_ABSTRACT_CLASS(PCompoundType) @@ -251,30 +321,133 @@ bool PNamedType::IsMatch(const void *id1, const void *id2) const return Outer == outer && TypeName == name; } +//========================================================================== +// +// PNamedType :: GetTypeIDs +// +//========================================================================== + +void PNamedType::GetTypeIDs(const void *&id1, const void *&id2) const +{ + id1 = Outer; + id2 = (void *)(intptr_t)TypeName; +} + /* PInt *******************************************************************/ IMPLEMENT_CLASS(PInt) +//========================================================================== +// +// PInt Default Constructor +// +//========================================================================== + +PInt::PInt() +: PBasicType(4, 4) +{ +} + +//========================================================================== +// +// PInt Parameterized Constructor +// +//========================================================================== + +PInt::PInt(unsigned int size, bool unsign) +: PBasicType(size, size), Unsigned(unsign) +{ +} + /* PFloat *****************************************************************/ IMPLEMENT_CLASS(PFloat) +//========================================================================== +// +// PFloat Default Constructor +// +//========================================================================== + +PFloat::PFloat() +: PBasicType(4, 4) +{ +} + +//========================================================================== +// +// PFloat Parameterized Constructor +// +//========================================================================== + +PFloat::PFloat(unsigned int size) +: PBasicType(size, size) +{ +} + /* PString ****************************************************************/ IMPLEMENT_CLASS(PString) +//========================================================================== +// +// PString Default Constructor +// +//========================================================================== + +PString::PString() +: PBasicType(sizeof(FString), __alignof(FString)) +{ +} + /* PName ******************************************************************/ IMPLEMENT_CLASS(PName) +//========================================================================== +// +// PName Default Constructor +// +//========================================================================== + +PName::PName() +: PInt(sizeof(FName), true) +{ + assert(sizeof(FName) == __alignof(FName)); +} + /* PSound *****************************************************************/ IMPLEMENT_CLASS(PSound) +//========================================================================== +// +// PSound Default Constructor +// +//========================================================================== + +PSound::PSound() +: PInt(sizeof(FSoundID), true) +{ + assert(sizeof(FSoundID) == __alignof(FSoundID)); +} + /* PColor *****************************************************************/ IMPLEMENT_CLASS(PColor) +//========================================================================== +// +// PColor Default Constructor +// +//========================================================================== + +PColor::PColor() +: PInt(sizeof(PalEntry), true) +{ + assert(sizeof(PalEntry) == __alignof(PalEntry)); +} + /* PPointer ***************************************************************/ IMPLEMENT_POINTY_CLASS(PPointer) @@ -295,6 +468,19 @@ bool PPointer::IsMatch(const void *id1, const void *id2) const return pointat == PointedType; } +//========================================================================== +// +// PPointer :: GetTypeIDs +// +//========================================================================== + +void PPointer::GetTypeIDs(const void *&id1, const void *&id2) const +{ + id1 = PointedType; + id2 = NULL; +} + + /* PClassPointer **********************************************************/ IMPLEMENT_POINTY_CLASS(PClassPointer) @@ -316,6 +502,20 @@ bool PClassPointer::IsMatch(const void *id1, const void *id2) const return classat == ClassRestriction; } +//========================================================================== +// +// PClassPointer :: GetTypeIDs +// +//========================================================================== + +void PClassPointer::GetTypeIDs(const void *&id1, const void *&id2) const +{ + assert(PointedType == RUNTIME_CLASS(PClass)); + id1 = PointedType; + id2 = ClassRestriction; +} + + /* PEnum ******************************************************************/ IMPLEMENT_POINTY_CLASS(PEnum) @@ -342,6 +542,18 @@ bool PArray::IsMatch(const void *id1, const void *id2) const return elemtype == ElementType && count == ElementCount; } +//========================================================================== +// +// PArray :: GetTypeIDs +// +//========================================================================== + +void PArray::GetTypeIDs(const void *&id1, const void *&id2) const +{ + id1 = ElementType; + id2 = (void *)(intptr_t)ElementCount; +} + /* PVector ****************************************************************/ IMPLEMENT_CLASS(PVector) @@ -352,6 +564,12 @@ IMPLEMENT_POINTY_CLASS(PDynArray) DECLARE_POINTER(ElementType) END_POINTERS +//========================================================================== +// +// PDynArray :: IsMatch +// +//========================================================================== + bool PDynArray::IsMatch(const void *id1, const void *id2) const { assert(id2 == NULL); @@ -360,6 +578,19 @@ bool PDynArray::IsMatch(const void *id1, const void *id2) const return elemtype == ElementType; } +//========================================================================== +// +// PDynArray :: GetTypeIDs +// +//========================================================================== + +void PDynArray::GetTypeIDs(const void *&id1, const void *&id2) const +{ + id1 = ElementType; + id2 = NULL; +} + + /* PMap *******************************************************************/ IMPLEMENT_POINTY_CLASS(PMap) @@ -381,6 +612,18 @@ bool PMap::IsMatch(const void *id1, const void *id2) const return keyty == KeyType && valty == ValueType; } +//========================================================================== +// +// PMap :: GetTypeIDs +// +//========================================================================== + +void PMap::GetTypeIDs(const void *&id1, const void *&id2) const +{ + id1 = KeyType; + id2 = ValueType; +} + /* PStruct ****************************************************************/ IMPLEMENT_CLASS(PStruct) @@ -415,6 +658,18 @@ bool PPrototype::IsMatch(const void *id1, const void *id2) const return *args == ArgumentTypes && *rets == ReturnTypes; } +//========================================================================== +// +// PPrototype :: GetTypeIDs +// +//========================================================================== + +void PPrototype::GetTypeIDs(const void *&id1, const void *&id2) const +{ + id1 = &ArgumentTypes; + id2 = &ReturnTypes; +} + //========================================================================== // // PPrototype :: PropagateMark @@ -970,7 +1225,7 @@ size_t PClass::PropagateMark() // //========================================================================== -PType *FTypeTable::FindType(PClass *metatype, void *parm1, void *parm2, size_t *bucketnum) +PType *FTypeTable::FindType(PClass *metatype, const void *parm1, const void *parm2, size_t *bucketnum) { size_t bucket = Hash(metatype, parm1, parm2) % HASH_SIZE; if (bucketnum != NULL) @@ -989,11 +1244,11 @@ PType *FTypeTable::FindType(PClass *metatype, void *parm1, void *parm2, size_t * //========================================================================== // -// FTypeTable :: AddType +// FTypeTable :: AddType - Fully Parameterized Version // //========================================================================== -void FTypeTable::AddType(PType *type, PClass *metatype, void *parm1, void *parm2, size_t bucket) +void FTypeTable::AddType(PType *type, PClass *metatype, const void *parm1, const void *parm2, size_t bucket) { #ifdef _DEBUG size_t bucketcheck; @@ -1003,6 +1258,29 @@ void FTypeTable::AddType(PType *type, PClass *metatype, void *parm1, void *parm2 #endif type->HashNext = TypeHash[bucket]; TypeHash[bucket] = type; + GC::WriteBarrier(type); +} + +//========================================================================== +// +// FTypeTable :: AddType - Simple Version +// +//========================================================================== + +void FTypeTable::AddType(PType *type) +{ + PClass *metatype; + const void *parm1, *parm2; + size_t bucket; + + metatype = type->GetClass()->TypeTableType; + type->GetTypeIDs(parm1, parm2); + bucket = Hash(metatype, parm1, parm2) % HASH_SIZE; + assert(FindType(metatype, parm1, parm2, NULL) == NULL && "Type must not be inserted more than once"); + + type->HashNext = TypeHash[bucket]; + TypeHash[bucket] = type; + GC::WriteBarrier(type); } //========================================================================== @@ -1011,7 +1289,7 @@ void FTypeTable::AddType(PType *type, PClass *metatype, void *parm1, void *parm2 // //========================================================================== -size_t FTypeTable::Hash(void *p1, void *p2, void *p3) +size_t FTypeTable::Hash(const void *p1, const void *p2, const void *p3) { size_t i1 = (size_t)p1; size_t i2 = (size_t)p2; @@ -1024,6 +1302,25 @@ size_t FTypeTable::Hash(void *p1, void *p2, void *p3) return (~i1 ^ i2) + i3 * 961748927; // i3 is multiplied by a prime } +//========================================================================== +// +// FTypeTable :: Mark +// +// Mark all types in this table for the garbage collector. +// +//========================================================================== + +void FTypeTable::Mark() +{ + for (int i = HASH_SIZE - 1; i >= 0; --i) + { + if (TypeHash[i] != NULL) + { + GC::Mark(TypeHash[i]); + } + } +} + #include "c_dispatch.h" CCMD(typetable) { diff --git a/src/dobjtype.h b/src/dobjtype.h index 538e4574e..4bf4fccd9 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -172,6 +172,7 @@ class PType : public DObject // and we can't define it until we've defined PClass. But we can't define that // without defining PType. DECLARE_ABSTRACT_CLASS(PType, DObject) + HAS_OBJECT_POINTERS; protected: enum { MetaClassNum = CLASSREG_PClassType }; public: @@ -183,6 +184,7 @@ public: PType *HashNext; // next type in this type table PType(); + PType(unsigned int size, unsigned int align); virtual ~PType(); // Returns true if this type matches the two identifiers. Referring to the @@ -193,6 +195,9 @@ public: // management. virtual bool IsMatch(const void *id1, const void *id2) const; + // Get the type IDs used by IsMatch + virtual void GetTypeIDs(const void *&id1, const void *&id2) const; + static void StaticInit(); }; @@ -201,6 +206,9 @@ public: class PBasicType : public PType { DECLARE_ABSTRACT_CLASS(PBasicType, PType); +public: + PBasicType(); + PBasicType(unsigned int size, unsigned int align); }; class PCompoundType : public PType @@ -219,6 +227,7 @@ public: PNamedType() : Outer(NULL) {} virtual bool IsMatch(const void *id1, const void *id2) const; + virtual void GetTypeIDs(const void *&id1, const void *&id2) const; }; // Basic types -------------------------------------------------------------- @@ -226,16 +235,28 @@ public: class PInt : public PBasicType { DECLARE_CLASS(PInt, PBasicType); +public: + PInt(unsigned int size, bool unsign); + + bool Unsigned; +protected: + PInt(); }; class PFloat : public PBasicType { DECLARE_CLASS(PFloat, PBasicType); +public: + PFloat(unsigned int size); +protected: + PFloat(); }; class PString : public PBasicType { DECLARE_CLASS(PString, PBasicType); +public: + PString(); }; // Variations of integer types ---------------------------------------------- @@ -243,16 +264,22 @@ class PString : public PBasicType class PName : public PInt { DECLARE_CLASS(PName, PInt); +public: + PName(); }; class PSound : public PInt { DECLARE_CLASS(PSound, PInt); +public: + PSound(); }; class PColor : public PInt { DECLARE_CLASS(PColor, PInt); +public: + PColor(); }; // Pointers ----------------------------------------------------------------- @@ -265,6 +292,7 @@ public: PType *PointedType; virtual bool IsMatch(const void *id1, const void *id2) const; + virtual void GetTypeIDs(const void *&id1, const void *&id2) const; }; class PClass; @@ -278,6 +306,7 @@ public: typedef PClass *Type2; virtual bool IsMatch(const void *id1, const void *id2) const; + virtual void GetTypeIDs(const void *&id1, const void *&id2) const; }; // Struct/class fields ------------------------------------------------------ @@ -318,6 +347,7 @@ public: unsigned int ElementCount; virtual bool IsMatch(const void *id1, const void *id2) const; + virtual void GetTypeIDs(const void *&id1, const void *&id2) const; }; // A vector is an array with extra operations. @@ -335,6 +365,7 @@ public: PType *ElementType; virtual bool IsMatch(const void *id1, const void *id2) const; + virtual void GetTypeIDs(const void *&id1, const void *&id2) const; }; class PMap : public PCompoundType @@ -346,6 +377,7 @@ public: PType *ValueType; virtual bool IsMatch(const void *id1, const void *id2) const; + virtual void GetTypeIDs(const void *&id1, const void *&id2) const; }; class PStruct : public PNamedType @@ -366,9 +398,10 @@ public: size_t PropagateMark(); virtual bool IsMatch(const void *id1, const void *id2) const; + virtual void GetTypeIDs(const void *&id1, const void *&id2) const; }; -// TBD: Should we support overloading? +// TBD: Should we really support overloading? class PFunction : public PNamedType { DECLARE_CLASS(PFunction, PNamedType); @@ -492,10 +525,12 @@ struct FTypeTable PType *TypeHash[HASH_SIZE]; - PType *FindType(PClass *metatype, void *parm1, void *parm2, size_t *bucketnum); - void AddType(PType *type, PClass *metatype, void *parm1, void *parm2, size_t bucket); + 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); + void AddType(PType *type); + void Mark(); - static size_t Hash(void *p1, void *p2, void *p3); + static size_t Hash(const void *p1, const void *p2, const void *p3); }; From 50d126e78b49d4ffa66b795dc597e5f839e0076b Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 24 Apr 2010 03:10:58 +0000 Subject: [PATCH 037/232] - Clear the TypeTable on shutdown so that the objects in it can be collected. SVN r2301 (scripting) --- src/dobjtype.cpp | 15 +++++++++++++++ src/dobjtype.h | 1 + 2 files changed, 16 insertions(+) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index d3aa01ce6..d757aff7c 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -790,6 +790,7 @@ void PClass::StaticShutdown () { delete[] uniqueFPs[i]; } + TypeTable.Clear(); bShutdown = true; } @@ -1321,6 +1322,20 @@ void FTypeTable::Mark() } } +//========================================================================== +// +// FTypeTable :: Clear +// +// Removes everything from the table. We let the garbage collector worry +// about deleting them. +// +//========================================================================== + +void FTypeTable::Clear() +{ + memset(TypeHash, 0, sizeof(TypeHash)); +} + #include "c_dispatch.h" CCMD(typetable) { diff --git a/src/dobjtype.h b/src/dobjtype.h index 4bf4fccd9..bdcff573d 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -529,6 +529,7 @@ struct FTypeTable void AddType(PType *type, PClass *metatype, const void *parm1, const void *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); }; From c043627cc1acc9742b778ed46abb277c987858f7 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sun, 6 Jun 2010 04:15:28 +0000 Subject: [PATCH 038/232] - 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) --- src/dobjtype.cpp | 306 +++++++++++-- src/dobjtype.h | 93 +++- src/memarena.cpp | 360 +++++++++++++++ src/memarena.h | 83 ++++ src/tarray.h | 17 + src/zscript/zcc-parse.lemon | 870 ++++++++++++++++++++++++++++++------ src/zscript/zcc_parser.cpp | 90 +--- src/zscript/zcc_parser.h | 373 ++++++++++++++++ zdoom.vcproj | 12 + 9 files changed, 1917 insertions(+), 287 deletions(-) create mode 100644 src/memarena.cpp create mode 100644 src/memarena.h create mode 100644 src/zscript/zcc_parser.h 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<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; 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<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 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 <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)); +} 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 <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; 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<type> */ -aggregate_type ::= CLASS class_restrictor. /* class<type> */ +%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<type> */ +aggregate_type ::= CLASS class_restrictor. /* class<type> */ + 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" > </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> From 85d869315bed4ebf15445bd5768f9c97d54620c4 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sun, 6 Jun 2010 21:04:55 +0000 Subject: [PATCH 039/232] - More AST'ing about. SVN r2359 (scripting) --- src/zscript/zcc-parse.lemon | 193 ++++++++++++++++++++++++++++-------- src/zscript/zcc_parser.h | 55 +++++++--- 2 files changed, 192 insertions(+), 56 deletions(-) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index 45ee171fa..c0d665a01 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -1,10 +1,15 @@ %include { +// Allocates a new AST node off the parse state's arena. #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 + +// If a is non-null, appends b to a. Otherwise, sets a to b. +#define SAFE_APPEND(a,b) \ + if (a == NULL) a = b; else a->AppendSibling(b); } %token_prefix ZCC_ @@ -87,23 +92,76 @@ opt_expr(X) ::= expr(A). } -/* A class definition. Can only occur at global scope. */ -class_definition ::= class_start class_body. +/************ Class Definition ************/ +/* Can only occur at global scope. */ + +%type class_definition{ZCC_Class *} +%type class_head{ZCC_Class *} +%type class_innards{ZCC_Class *} +%type class_body{ZCC_TreeNode *} + +class_definition(X) ::= class_head(A) class_body(B). { -/* stat->CurrClass = NULL;*/ + A->Body = B; + X = A; } -class_start ::= CLASS IDENTIFIER class_ancestry class_flags. +class_head(X) ::= CLASS dottable_id(A) class_ancestry(B) class_flags(C). +{ + NEW_AST_NODE(Class,head); + head->ClassName = A; + head->ParentName = B; + head->Flags = C.Flags; + head->Replaces = C.Replaces; + X = head; +} -%type class_ancestry {ENamedName} -class_ancestry(X) ::= . { X = NAME_Object; } -class_ancestry(X) ::= COLON IDENTIFIER(A). { X = ENamedName(A.Int); } +%type class_ancestry{ZCC_Identifier *} +class_ancestry(X) ::= . { X = NULL; } +class_ancestry(X) ::= COLON dottable_id(A). { X = A; } -class_flags ::= . -class_flags ::= class_flags ABSTRACT. -class_flags ::= class_flags NATIVE. -class_flags ::= class_flags REPLACES IDENTIFIER. +%type class_flags{ClassFlagsBlock} +%include{ + struct ClassFlagsBlock { + VM_UWORD Flags; + ZCC_Identifier *Replaces; + }; +} +class_flags(X) ::= . { X.Flags = 0; X.Replaces = NULL; } +class_flags(X) ::= class_flags(A) ABSTRACT. { X.Flags = A.Flags | 0/*FIXME*/; X.Replaces = A.Replaces; } +class_flags(X) ::= class_flags(A) NATIVE. { X.Flags = A.Flags | 0/*FIXME*/; X.Replaces = A.Replaces; } +class_flags(X) ::= class_flags(A) REPLACES dottable_id(B). { X.Flags = A.Flags; X.Replaces = B; } +/*----- Dottable Identifier -----*/ +// This can be either a single identifier or two identifiers connected by a . + +%type dottable_id{ZCC_Identifier *} + +dottable_id(X) ::= IDENTIFIER(A). +{ + NEW_AST_NODE(Identifier,id); + id->Id = A.Name(); + X = id; +} +dottable_id(X) ::= IDENTIFIER(A) DOT IDENTIFIER(B). +{ + NEW_AST_NODE(Identifier,id1); + NEW_AST_NODE(Identifier,id2); + id1->Id = A.Name(); + id2->Id = B.Name(); + id1->AppendSibling(id2); + X = id1; +} + +/*------ Class Body ------*/ +// Body is a list of: +// * variable definitions +// * function definitions +// * enum definitions +// * struct definitions +// * state definitions +// * constants +// * defaults class_body ::= SEMICOLON class_innards EOF. class_body ::= LBRACE class_innards RBRACE. @@ -111,7 +169,10 @@ class_body ::= LBRACE class_innards RBRACE. class_innards ::= . class_innards ::= class_innards class_member. -/* Classes can define variables, functions, enums, structs, states, constants, and defaults. */ +%type struct_def{ZCC_Struct *} +%type enum_def {ZCC_Enum *} +%type states_def {ZCC_States *} + class_member ::= declarator. class_member ::= enum_def. class_member ::= struct_def. @@ -119,25 +180,79 @@ class_member ::= states_def. class_member ::= default_def. class_member ::= const_def. -/* Structs can define variables, enums, and structs. */ -struct_def ::= STRUCT IDENTIFIER LBRACE struct_body RBRACE opt_semicolon. -struct_member ::= declarator_no_fun. -struct_member ::= enum_def. +/*----- Struct Definition -----*/ +/* Structs can define variables, enums<s>, and structs</s>. */ +%type struct_body{ZCC_TreeNode *} +%type struct_member{ZCC_TreeNode *} + +struct_def(X) ::= STRUCT IDENTIFIER(A) LBRACE struct_body(B) RBRACE opt_semicolon. +{ + NEW_AST_NODE(Struct,def); + def->StructName = A.Name(); + def->Body = B; + X = def; +} + +struct_body(X) ::= error. { X = NULL; } +struct_body(X) ::= struct_member(A). { X = A; } +struct_body(X) ::= struct_member(A) struct_body(B). { X = A; A->AppendSibling(B); } + +struct_member(X) ::= declarator_no_fun(A). { X = A; } +struct_member(X) ::= enum_def(A). { X = A; } + + +/*----- Enum Definition -----*/ /* Enumerators are lists of named integers. */ -enum_def ::= ENUM IDENTIFIER enum_type LBRACE enum_list opt_comma RBRACE opt_semicolon. -enum_type ::= . -enum_type ::= COLON int_type. +%type enum_type {EZCCIntType} +%type enum_list {ZCC_EnumNode *} +%type enumerator {ZCC_EnumNode *} -enum_list ::= enumerator. -enum_list ::= enum_list COMMA enumerator. +enum_def(X) ::= ENUM IDENTIFIER(A) enum_type(B) LBRACE enum_list(C) opt_comma RBRACE opt_semicolon. +{ + NEW_AST_NODE(Enum,def); + def->EnumName = A.Name(); + def->EnumType = B; + def->Elements = C; + X = def; +} -enumerator ::= IDENTIFIER. -enumerator ::= IDENTIFIER EQ expr. /* Expression must be constant. */ +enum_type(X) ::= . { X = ZCCINT_Auto; } +enum_type(X) ::= COLON int_type(A). { X = A; } -/* States */ -states_def ::= STATES scanner_mode LBRACE states_body RBRACE. +enum_list(X) ::= error. { X = NULL; } +enum_list(X) ::= enumerator(A). { X = A; } +enum_list(X) ::= enum_list(A) COMMA enumerator(B). { X = A; A->AppendSibling(B); } + +enumerator(X) ::= IDENTIFIER(A). +{ + NEW_AST_NODE(EnumNode,node); + node->ElemName = A.Name(); + node->ElemValue = NULL; + X = node; +} +enumerator(X) ::= IDENTIFIER(A) EQ expr(B). /* Expression must be constant. */ +{ + NEW_AST_NODE(EnumNode,node); + node->ElemName = A.Name(); + node->ElemValue = B; + X = node; +} + +/************ States ************/ + +%type states_body {ZCC_StatePart *} +%type state_line {ZCC_StatePart *} +%type state_label {ZCC_StatePart *} +%type state_flow {ZCC_StatePart *} + +states_def(X) ::= STATES scanner_mode LBRACE states_body(A) RBRACE. +{ + NEW_AST_NODE(States,def); + def->Body = A; + X = def; +} /* We use a special scanner mode to allow for sprite names and frame characters * to not be quoted even if they contain special characters. The scanner_mode @@ -152,12 +267,11 @@ states_def ::= STATES scanner_mode LBRACE states_body RBRACE. */ scanner_mode ::= . { stat->sc.SetStateMode(true); } -states_body ::= . -states_body ::= error. -/*states_body ::= states_body LABELID.*/ -states_body ::= states_body state_line. -states_body ::= states_body state_label. -states_body ::= states_body state_flow. +states_body(X) ::= . { X = NULL; } +states_body(X) ::= error. { X = NULL; } +states_body(X) ::= states_body(A) state_line(B). { SAFE_APPEND(A,B); X = A; } +states_body(X) ::= states_body(A) state_label(B). { SAFE_APPEND(A,B); X = A; } +states_body(X) ::= states_body(A) state_flow(B). { SAFE_APPEND(A,B); X = A; } state_label ::= NWS(A) COLON. { Printf("Label %s\n", FName(ENamedName(A.Int)).GetChars()); } @@ -201,15 +315,15 @@ dotted_identifier ::= dotted_identifier DOT IDENTIFIER. default_def ::= DEFAULT compound_statement. /* Type names */ -%type int_type {PType *} +%type int_type {EZCCIntType} %type type_name {PType *} -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; } +int_type(X) ::= SBYTE. { X = ZCCINT_SInt8; } +int_type(X) ::= BYTE. { X = ZCCINT_UInt8; } +int_type(X) ::= SHORT. { X = ZCCINT_SInt16; } +int_type(X) ::= USHORT. { X = ZCCINT_UInt16; } +int_type(X) ::= INT. { X = ZCCINT_SInt32; } +int_type(X) ::= UINT. { X = ZCCINT_UInt32; } type_name(X) ::= BOOL. { /*FIXME*/ X = TypeBool; } type_name(X) ::= int_type(A). { X = A; } @@ -358,9 +472,6 @@ func_param_flags ::= func_param_flags IN. func_param_flags ::= func_param_flags OUT. func_param_flags ::= func_param_flags OPTIONAL. -struct_body ::= struct_member. -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. diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index c1f3cc014..28ed6c2e1 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -14,16 +14,20 @@ union ZCCToken int Int; double Float; FString *String; + + ENamedName Name() { return ENamedName(Int); } }; // Syntax tree structures. enum EZCCTreeNodeType { + AST_Identifier, AST_Class, AST_Struct, AST_Enum, AST_EnumNode, AST_States, + AST_StatePart, AST_StateLabel, AST_StateGoto, AST_StateLine, @@ -58,6 +62,16 @@ enum EZCCTreeNodeType AST_LocalVarStmt, }; +enum EZCCIntType +{ + ZCCINT_SInt8, + ZCCINT_UInt8, + ZCCINT_SInt16, + ZCCINT_UInt16, + ZCCINT_SInt32, + ZCCINT_UInt32, + ZCCINT_Auto, // for enums, autoselect appropriately sized int +}; enum EZCCExprType { @@ -151,49 +165,60 @@ struct ZCC_TreeNode } }; +struct ZCC_Identifier : ZCC_TreeNode +{ + ENamedName Id; +}; + struct ZCC_Class : ZCC_TreeNode { - FName ClassName; - FName ParentName; + ZCC_Identifier *ClassName; + ZCC_Identifier *ParentName; + ZCC_Identifier *Replaces; VM_UWORD Flags; ZCC_TreeNode *Body; }; struct ZCC_Struct : ZCC_TreeNode { - FName StructName; + ENamedName StructName; ZCC_TreeNode *Body; }; struct ZCC_Enum : ZCC_TreeNode { - FName EnumName; + ENamedName EnumName; + EZCCIntType EnumType; struct ZCC_EnumNode *Elements; }; struct ZCC_EnumNode : ZCC_TreeNode { - FName ElemName; + ENamedName ElemName; ZCC_TreeNode *ElemValue; }; struct ZCC_States : ZCC_TreeNode { - ZCC_TreeNode *Body; + struct ZCC_StatePart *Body; }; -struct ZCC_StateLabel : ZCC_TreeNode +struct ZCC_StatePart : ZCC_TreeNode { - FName Label; }; -struct ZCC_StateGoto : ZCC_TreeNode +struct ZCC_StateLabel : ZCC_StatePart +{ + ENamedName Label; +}; + +struct ZCC_StateGoto : ZCC_StatePart { ZCC_TreeNode *Label; ZCC_TreeNode *Offset; }; -struct ZCC_StateLine : ZCC_TreeNode +struct ZCC_StateLine : ZCC_StatePart { char Sprite[4]; FString *Frames; @@ -225,7 +250,7 @@ struct ZCC_Type : ZCC_TreeNode struct ZCC_BasicType : ZCC_Type { PType *Type; - FName TypeName; + ENamedName TypeName; }; struct ZCC_MapType : ZCC_Type @@ -241,12 +266,12 @@ struct ZCC_DynArrayType : ZCC_Type struct ZCC_ClassType : ZCC_Type { - FName Restriction; + ENamedName Restriction; }; struct ZCC_ExprID : ZCC_Expression { - FName Identifier; + ENamedName Identifier; }; struct ZCC_ExprString : ZCC_Expression @@ -267,7 +292,7 @@ struct ZCC_ExprFloat : ZCC_Expression struct ZCC_FuncParm : ZCC_TreeNode { ZCC_Expression *Value; - FName Label; + ENamedName Label; }; struct ZCC_ExprFuncCall : ZCC_Expression @@ -279,7 +304,7 @@ struct ZCC_ExprFuncCall : ZCC_Expression struct ZCC_ExprMemberAccess : ZCC_Expression { ZCC_Expression *Left; - FName Right; + ENamedName Right; }; struct ZCC_ExprUnary : ZCC_Expression From 9d931ed10c985d87d6a09c7f36770cfad3381429 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sun, 11 Jul 2010 18:53:41 +0000 Subject: [PATCH 040/232] - Make AST nodes for states. SVN r2425 (scripting) --- src/zscript/zcc-parse.lemon | 119 +++++++++++++++++++++++------------- src/zscript/zcc_parser.h | 40 ++++++++---- 2 files changed, 106 insertions(+), 53 deletions(-) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index c0d665a01..63b6a4b91 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -143,14 +143,12 @@ dottable_id(X) ::= IDENTIFIER(A). id->Id = A.Name(); X = id; } -dottable_id(X) ::= IDENTIFIER(A) DOT IDENTIFIER(B). +dottable_id(X) ::= dottable_id(A) DOT IDENTIFIER(B). { - NEW_AST_NODE(Identifier,id1); NEW_AST_NODE(Identifier,id2); - id1->Id = A.Name(); id2->Id = B.Name(); - id1->AppendSibling(id2); - X = id1; + A->AppendSibling(id2); + X = A; } /*------ Class Body ------*/ @@ -246,6 +244,20 @@ enumerator(X) ::= IDENTIFIER(A) EQ expr(B). /* Expression must be constant. */ %type state_line {ZCC_StatePart *} %type state_label {ZCC_StatePart *} %type state_flow {ZCC_StatePart *} +%type state_flow_type {ZCC_StatePart *} +%type state_goto_offset {ZCC_Expression *} +%type state_action {ZCC_TreeNode *} +%type state_call {ZCC_ExprFuncCall *} + +%include +{ + struct StateOpts + { + ZCC_Expression *Offset; + bool Bright; + }; +} +%type state_opts {StateOpts} states_def(X) ::= STATES scanner_mode LBRACE states_body(A) RBRACE. { @@ -273,43 +285,76 @@ states_body(X) ::= states_body(A) state_line(B). { SAFE_APPEND(A,B); X = A; } states_body(X) ::= states_body(A) state_label(B). { SAFE_APPEND(A,B); X = A; } states_body(X) ::= states_body(A) state_flow(B). { SAFE_APPEND(A,B); X = A; } -state_label ::= NWS(A) COLON. -{ Printf("Label %s\n", FName(ENamedName(A.Int)).GetChars()); } +state_label(X) ::= NWS(A) COLON. +{ + NEW_AST_NODE(StateLabel, label); + label->Label = A.Name(); + X = label; +} -state_flow ::= state_flow_type scanner_mode SEMICOLON. -state_flow_type ::= STOP. -state_flow_type ::= WAIT. -state_flow_type ::= FAIL. -state_flow_type ::= LOOP. -state_flow_type ::= GOTO dotted_identifier state_goto_offset. +state_flow(X) ::= state_flow_type(A) scanner_mode SEMICOLON. { X = A; } -state_goto_offset ::= . -state_goto_offset ::= PLUS expr. /* Must evaluate to an integer constant. */ +state_flow_type(X) ::= STOP. { NEW_AST_NODE(StateStop, flow); X = flow; } +state_flow_type(X) ::= WAIT. { NEW_AST_NODE(StateWait, flow); X = flow; } +state_flow_type(X) ::= FAIL. { NEW_AST_NODE(StateFail, flow); X = flow; } +state_flow_type(X) ::= LOOP. { NEW_AST_NODE(StateLoop, flow); X = flow; } +state_flow_type(X) ::= GOTO dottable_id(A) state_goto_offset(B). +{ + NEW_AST_NODE(StateGoto, flow); + flow->Label = A; + flow->Offset = B; + X = flow; +} -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_goto_offset(X) ::= . { X = NULL; } +state_goto_offset(X) ::= PLUS expr(A). { X = A; } /* Must evaluate to a non-negative integer constant. */ -state_opts ::= . -state_opts ::= state_opts BRIGHT. -state_opts ::= state_opts OFFSET LPAREN expr COMMA expr RPAREN. -state_opts ::= state_opts LIGHT LPAREN light_list RPAREN. +state_line(X) ::= NWS(A) NWS(B) expr state_opts(C) state_action(D). +{ + NEW_AST_NODE(StateLine, line); + const char *sprite = FName(A.Name()).GetChars(); + memset(line, 0, sizeof(*line)); + if (strlen(sprite) != 4) + { + Printf("Sprite name '%s' must be four characters", sprite); + } + else + { + memcpy(line->Sprite, sprite, 4); + } + line->Frames = stat->Strings.Alloc(FName(B.Name()).GetChars()); + line->bBright = C.Bright; + line->Offset = C.Offset; + line->Action = D; + X = line; +} + +state_opts(X) ::= . { StateOpts opts; opts.Offset = NULL; opts.Bright = false; X = opts; } +state_opts(X) ::= state_opts(A) BRIGHT. { A.Bright = true; X = A; } +state_opts(X) ::= state_opts(A) OFFSET LPAREN expr(B) COMMA expr(C) RPAREN. { A.Offset = B; B->AppendSibling(C); X = A; } +state_opts(X) ::= state_opts(A) LIGHT LPAREN light_list RPAREN. { X = A; } light_list ::= STRCONST. light_list ::= light_list COMMA STRCONST. /* A state action can be either a compound statement or a single action function call. */ -state_action ::= LBRACE statement_list scanner_mode RBRACE. -state_action ::= LBRACE error scanner_mode RBRACE. -state_action ::= state_call scanner_mode SEMICOLON. +state_action(X) ::= LBRACE statement_list(A) scanner_mode RBRACE. { X = A; } +state_action(X) ::= LBRACE error scanner_mode RBRACE. { X = NULL; } +state_action(X) ::= state_call(A) scanner_mode SEMICOLON. { X = A; } -state_call ::= . -state_call ::= IDENTIFIER state_call_parms. -state_call_parms ::= . -state_call_parms ::= LPAREN opt_expr_list RPAREN. -state_call_parms ::= LPAREN error RPAREN. +state_call(X) ::= . { X = NULL; } +state_call(X) ::= IDENTIFIER(A) func_params(B). +{ + NEW_AST_NODE(ExprFuncCall, expr); + NEW_AST_NODE(ExprID, func); -dotted_identifier ::= IDENTIFIER. -dotted_identifier ::= dotted_identifier DOT IDENTIFIER. + func->Operation = PEX_ID; + func->Identifier = A.Name(); + expr->Operation = PEX_FuncCall; + expr->Function = func; + expr->Parameters = B; + X = expr; +} /* Definition of a default class instance. */ default_def ::= DEFAULT compound_statement. @@ -497,7 +542,7 @@ primary(X) ::= IDENTIFIER(A). { NEW_AST_NODE(ExprID, expr); expr->Operation = PEX_ID; - expr->Identifier = ENamedName(A.Int); + expr->Identifier = A.Name(); X = expr; } primary(X) ::= SUPER. @@ -769,18 +814,8 @@ expr(X) ::= expr(A) QUESTION expr(B) COLON expr(C). /************ 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; diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index 28ed6c2e1..ce340f5db 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -29,6 +29,10 @@ enum EZCCTreeNodeType AST_States, AST_StatePart, AST_StateLabel, + AST_StateStop, + AST_StateWait, + AST_StateFail, + AST_StateLoop, AST_StateGoto, AST_StateLine, AST_VarName, @@ -212,21 +216,20 @@ struct ZCC_StateLabel : ZCC_StatePart ENamedName Label; }; -struct ZCC_StateGoto : ZCC_StatePart +struct ZCC_StateStop : ZCC_StatePart { - ZCC_TreeNode *Label; - ZCC_TreeNode *Offset; }; -struct ZCC_StateLine : ZCC_StatePart +struct ZCC_StateWait : ZCC_StatePart +{ +}; + +struct ZCC_StateFail : ZCC_StatePart +{ +}; + +struct ZCC_StateLoop : ZCC_StatePart { - char Sprite[4]; - FString *Frames; - BITFIELD bBright:1; - BITFIELD bHasOffset:1; - int OffsetX; - int OffsetY; - ZCC_TreeNode *Action; }; struct ZCC_Expression : ZCC_TreeNode @@ -234,6 +237,21 @@ struct ZCC_Expression : ZCC_TreeNode EZCCExprType Operation; }; +struct ZCC_StateGoto : ZCC_StatePart +{ + ZCC_Identifier *Label; + ZCC_Expression *Offset; +}; + +struct ZCC_StateLine : ZCC_StatePart +{ + char Sprite[4]; + BITFIELD bBright:1; + FString *Frames; + ZCC_Expression *Offset; + ZCC_TreeNode *Action; +}; + struct ZCC_VarName : ZCC_TreeNode { bool bIsArray; From 081ebbb64b59cdd5d05ddd24aa6d1ff823dff169 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 10 Aug 2010 04:25:52 +0000 Subject: [PATCH 041/232] - I have decided to opt for simplicity over C-like-ness and group array sizes with the rest of the type declaration rather than split it up after the variable name. - More AST work. At this rate, maybe I'll finally be building a complete AST by the end of the month! SVN r2499 (scripting) --- src/sc_man_scanner.re | 1 + src/sc_man_tokens.h | 1 + src/zscript/zcc-parse.lemon | 105 +++++++++++++++++++++--------------- src/zscript/zcc_parser.cpp | 1 + src/zscript/zcc_parser.h | 47 ++++++++++++++-- 5 files changed, 107 insertions(+), 48 deletions(-) diff --git a/src/sc_man_scanner.re b/src/sc_man_scanner.re index d8070b53a..437887d87 100644 --- a/src/sc_man_scanner.re +++ b/src/sc_man_scanner.re @@ -175,6 +175,7 @@ std2: 'meta' { RET(TK_Meta); } 'deprecated' { RET(TK_Deprecated); } 'action' { RET(TK_Action); } + 'readonly' { RET(TK_ReadOnly); } /* other DECORATE top level keywords */ '#include' { RET(TK_Include); } diff --git a/src/sc_man_tokens.h b/src/sc_man_tokens.h index de0815447..e98c457b5 100644 --- a/src/sc_man_tokens.h +++ b/src/sc_man_tokens.h @@ -130,4 +130,5 @@ xx(TK_Fail, "'fail'") xx(TK_Wait, "'wait'") xx(TK_Meta, "'meta'") xx(TK_Deprecated, "'deprecated'") +xx(TK_ReadOnly, "'readonly'") #undef xx diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index 63b6a4b91..459432dd1 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -170,6 +170,7 @@ class_innards ::= class_innards class_member. %type struct_def{ZCC_Struct *} %type enum_def {ZCC_Enum *} %type states_def {ZCC_States *} +%type const_def {ZCC_ConstantDef *} class_member ::= declarator. class_member ::= enum_def. @@ -183,6 +184,7 @@ class_member ::= const_def. %type struct_body{ZCC_TreeNode *} %type struct_member{ZCC_TreeNode *} +%type declarator_no_fun {ZCC_TreeNode *} struct_def(X) ::= STRUCT IDENTIFIER(A) LBRACE struct_body(B) RBRACE opt_semicolon. { @@ -343,7 +345,7 @@ state_action(X) ::= LBRACE error scanner_mode RBRACE. { X = NULL; } state_action(X) ::= state_call(A) scanner_mode SEMICOLON. { X = A; } state_call(X) ::= . { X = NULL; } -state_call(X) ::= IDENTIFIER(A) func_params(B). +state_call(X) ::= IDENTIFIER(A) func_expr_list(B). { NEW_AST_NODE(ExprFuncCall, expr); NEW_AST_NODE(ExprID, func); @@ -394,10 +396,13 @@ vector_size(X) ::= LT INTCONST(A) GT. { X = A.Int; } SBYTE BYTE SHORT USHORT INT UINT BOOL FLOAT DOUBLE STRING VECTOR NAME. /* Aggregate types */ -%type aggregate_type {PType *} -%type type {PType *} -%type type_or_array {PType *} +%type aggregate_type {ZCC_Type *} +%type type {ZCC_Type *} +%type type_list {ZCC_Type *} +%type type_list_or_void {ZCC_Type *} +%type type_or_array {ZCC_Type *} %type class_restrictor {PClass *} +%type array_size{ZCC_Expression *} aggregate_type ::= MAP LT type_or_array COMMA type_or_array GT. /* Hash table */ aggregate_type ::= ARRAY LT type_or_array GT. /* TArray<type> */ @@ -406,24 +411,24 @@ aggregate_type ::= CLASS class_restrictor. /* class<type> */ class_restrictor ::= . class_restrictor ::= LT IDENTIFIER GT. -type(X) ::= type_name(A). { X = A; } -type(X) ::= aggregate_type(A). { X = A; } +type(X) ::= type_name(A). { X = A; A->ArraySize = NULL; } +type(X) ::= aggregate_type(A). { X = A; A->ArraySize = NULL; } -type_or_array ::= type. -type_or_array ::= type array_size. +type_or_array(X) ::= type(A). { X = A; } +type_or_array(X) ::= type(A) array_size(B). { X = A; A->ArraySize = B; } -type_list ::= type_or_array. /* A comma-separated list of types */ -type_list ::= type_list COMMA type_or_array. +type_list(X) ::= type_or_array(A). { X = A; }/* A comma-separated list of types */ +type_list(X) ::= type_list(A) COMMA type_or_array(B). { X = A; A->AppendSibling(B); } -type_list_or_void ::= VOID. -type_list_or_void ::= type_list. +type_list_or_void(X) ::= VOID. { X = NULL; } +type_list_or_void(X) ::= type_list(A). { X = A; } -%type array_size{ZCC_Expression *} array_size(X) ::= LBRACKET opt_expr(A) RBRACKET. { if (A == NULL) { NEW_AST_NODE(Expression,nil); + nil->Operation = PEX_Nil; X = nil; } else @@ -436,6 +441,7 @@ array_size(X) ::= array_size(A) LBRACKET opt_expr(B) RBRACKET. if (B == NULL) { NEW_AST_NODE(Expression,nil); + nil->Operation = PEX_Nil; A->AppendSibling(nil); } else @@ -459,23 +465,15 @@ variables_or_function ::= error SEMICOLON. %type variable_name{ZCC_VarName *} %type variable_list{ZCC_VarName *} +%type decl_flags{int} 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; @@ -486,16 +484,17 @@ variable_list(X) ::= variable_list(A) COMMA variable_name(B). X = A; } -decl_flags ::= . -decl_flags ::= decl_flags NATIVE. -decl_flags ::= decl_flags STATIC. -decl_flags ::= decl_flags PRIVATE. -decl_flags ::= decl_flags PROTECTED. -decl_flags ::= decl_flags LATENT. -decl_flags ::= decl_flags FINAL. -decl_flags ::= decl_flags META. -decl_flags ::= decl_flags ACTION. -decl_flags ::= decl_flags DEPRECATED LPAREN string_constant RPAREN. +decl_flags(X) ::= . { X = 0; } +decl_flags(X) ::= decl_flags(A) NATIVE. { X = A | ZCC_Native; } +decl_flags(X) ::= decl_flags(A) STATIC. { X = A | ZCC_Static; } +decl_flags(X) ::= decl_flags(A) PRIVATE. { X = A | ZCC_Private; } +decl_flags(X) ::= decl_flags(A) PROTECTED. { X = A | ZCC_Protected; } +decl_flags(X) ::= decl_flags(A) LATENT. { X = A | ZCC_Latent; } +decl_flags(X) ::= decl_flags(A) FINAL. { X = A | ZCC_Final; } +decl_flags(X) ::= decl_flags(A) META. { X = A | ZCC_Meta; } +decl_flags(X) ::= decl_flags(A) ACTION. { X = A | ZCC_Action; } +decl_flags(X) ::= decl_flags(A) READONLY. { X = A | ZCC_ReadOnly; } +decl_flags(X) ::= decl_flags(A) DEPRECATED. { X = A | ZCC_Deprecated; } func_const ::= . func_const ::= CONST. @@ -503,22 +502,40 @@ func_const ::= CONST. opt_func_body ::= SEMICOLON. opt_func_body ::= function_body. -func_params ::= . /* empty */ -func_params ::= VOID. -func_params ::= func_param_list. +%type func_params {ZCC_FuncParamDecl *} +%type func_param_list {ZCC_FuncParamDecl *} +%type func_param {ZCC_FuncParamDecl *} +%type func_param_flags {int} -func_param_list ::= func_param. -func_param_list ::= func_param COMMA func_param_list. +func_params(X) ::= . /* empty */ { X = NULL; } +func_params(X) ::= VOID. { X = NULL; } +func_params(X) ::= func_param_list(A). { X = A; } -func_param ::= func_param_flags type variable_name. +func_param_list(X) ::= func_param(A). { X = A; } +func_param_list(X) ::= func_param(A) COMMA func_param_list(B). { X = A; A->AppendSibling(B); } -func_param_flags ::= . -func_param_flags ::= func_param_flags IN. -func_param_flags ::= func_param_flags OUT. -func_param_flags ::= func_param_flags OPTIONAL. +func_param(X) ::= func_param_flags(A) type(B) IDENTIFIER(C). +{ + NEW_AST_NODE(FuncParamDecl,parm); + parm->Type = B; + parm->Name = C.Name(); + parm->Flags = A; + X = parm; +} + +func_param_flags(X) ::= . { X = 0; } +func_param_flags(X) ::= func_param_flags(A) IN. { X = A | ZCC_In; } +func_param_flags(X) ::= func_param_flags(A) OUT. { X = A | ZCC_Out; } +func_param_flags(X) ::= func_param_flags(A) OPTIONAL. { X = A | ZCC_Optional; } /* Like UnrealScript, a constant's type is implied by its value's type. */ -const_def ::= CONST IDENTIFIER EQ expr SEMICOLON. +const_def(X) ::= CONST IDENTIFIER(A) EQ expr(B) SEMICOLON. +{ + NEW_AST_NODE(ConstantDef,def); + def->Name = A.Name(); + def->Value = B; + X = def; +} /************ Expressions ************/ diff --git a/src/zscript/zcc_parser.cpp b/src/zscript/zcc_parser.cpp index eab49046a..69e501d10 100644 --- a/src/zscript/zcc_parser.cpp +++ b/src/zscript/zcc_parser.cpp @@ -76,6 +76,7 @@ static void InitTokenMap() TOKENDEF(TK_Final, ZCC_FINAL); TOKENDEF(TK_Meta, ZCC_META); TOKENDEF(TK_Deprecated, ZCC_DEPRECATED); + TOKENDEF(TK_ReadOnly, ZCC_READONLY); TOKENDEF('{', ZCC_LBRACE); TOKENDEF('}', ZCC_RBRACE); TOKENDEF(TK_Struct, ZCC_STRUCT); diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index ce340f5db..f14261c28 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -18,6 +18,31 @@ union ZCCToken ENamedName Name() { return ENamedName(Int); } }; +// Variable / Function modifiers +enum +{ + ZCC_Native = 1 << 0, + ZCC_Static = 1 << 1, + ZCC_Private = 1 << 2, + ZCC_Protected = 1 << 3, + ZCC_Latent = 1 << 4, + ZCC_Final = 1 << 5, + ZCC_Meta = 1 << 6, + ZCC_Action = 1 << 7, + ZCC_Deprecated = 1 << 8, + ZCC_ReadOnly = 1 << 9, +}; + +// Function parameter modifiers +enum +{ + ZCC_In = 1 << 0, + ZCC_Out = 1 << 1, + ZCC_Optional = 1 << 2, +}; + + + // Syntax tree structures. enum EZCCTreeNodeType { @@ -64,6 +89,8 @@ enum EZCCTreeNodeType AST_CaseStmt, AST_AssignStmt, AST_LocalVarStmt, + AST_FuncParamDecl, + AST_ConstantDef, }; enum EZCCIntType @@ -79,6 +106,8 @@ enum EZCCIntType enum EZCCExprType { + PEX_Nil, + PEX_ID, PEX_Super, PEX_Self, @@ -254,15 +283,12 @@ struct ZCC_StateLine : ZCC_StatePart struct ZCC_VarName : ZCC_TreeNode { - bool bIsArray; - ZCC_Expression *ArraySize; ENamedName Name; }; struct ZCC_Type : ZCC_TreeNode { - BITFIELD bIsArray:1; - ZCC_Expression *ArraySize; + ZCC_Expression *ArraySize; // NULL if not an array }; struct ZCC_BasicType : ZCC_Type @@ -414,3 +440,16 @@ struct ZCC_LocalVarStmt : ZCC_Statement ZCC_VarName *Vars; ZCC_Expression *Inits; }; + +struct ZCC_FuncParamDecl : ZCC_TreeNode +{ + ZCC_Type *Type; + ENamedName Name; + int Flags; +}; + +struct ZCC_ConstantDef : ZCC_TreeNode +{ + ENamedName Name; + ZCC_Expression *Value; +}; From 12c6ddfbfbd15331b17193ed636c3ec4bef9c275 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 7 Sep 2010 04:11:32 +0000 Subject: [PATCH 042/232] - So, progress... SVN r2707 (scripting) --- src/zscript/zcc-parse.lemon | 215 +++++++++++++++++++++++++++++------- src/zscript/zcc_parser.h | 50 +++++++-- 2 files changed, 215 insertions(+), 50 deletions(-) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index 459432dd1..2f8c225ae 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -64,6 +64,10 @@ %left DOT LPAREN LBRACKET. %left SCOPE. +%type declarator {ZCC_Declarator *} +%type declarator_no_fun {ZCC_Declarator *} +%type opt_func_body {ZCC_CompoundStmt *} +%type function_body {ZCC_CompoundStmt *} main ::= translation_unit. { stat->sc.ScriptMessage("Parse complete\n"); } @@ -180,7 +184,7 @@ class_member ::= default_def. class_member ::= const_def. /*----- Struct Definition -----*/ -/* Structs can define variables, enums<s>, and structs</s>. */ +/* Structs can define variables and enums. */ %type struct_body{ZCC_TreeNode *} %type struct_member{ZCC_TreeNode *} @@ -205,7 +209,7 @@ struct_member(X) ::= enum_def(A). { X = A; } /*----- Enum Definition -----*/ /* Enumerators are lists of named integers. */ -%type enum_type {EZCCIntType} +%type enum_type {EZCCBuiltinType} %type enum_list {ZCC_EnumNode *} %type enumerator {ZCC_EnumNode *} @@ -362,33 +366,67 @@ state_call(X) ::= IDENTIFIER(A) func_expr_list(B). default_def ::= DEFAULT compound_statement. /* Type names */ -%type int_type {EZCCIntType} -%type type_name {PType *} +%type int_type {EZCCBuiltinType} +%type type_name {ZCC_BasicType *} +%type type_name1 {EZCCBuiltinType} +%type vector_size {EZCCBuiltinType} -int_type(X) ::= SBYTE. { X = ZCCINT_SInt8; } -int_type(X) ::= BYTE. { X = ZCCINT_UInt8; } -int_type(X) ::= SHORT. { X = ZCCINT_SInt16; } -int_type(X) ::= USHORT. { X = ZCCINT_UInt16; } -int_type(X) ::= INT. { X = ZCCINT_SInt32; } -int_type(X) ::= UINT. { X = ZCCINT_UInt32; } +int_type(X) ::= SBYTE. { X = ZCC_SInt8; } +int_type(X) ::= BYTE. { X = ZCC_UInt8; } +int_type(X) ::= SHORT. { X = ZCC_SInt16; } +int_type(X) ::= USHORT. { X = ZCC_UInt16; } +int_type(X) ::= INT. { X = ZCC_SInt32; } +int_type(X) ::= UINT. { X = ZCC_UInt32; } -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) */ +type_name1(X) ::= BOOL. { X = ZCC_Bool; } +type_name1(X) ::= int_type(A). { X = A; } +type_name1(X) ::= FLOAT. { X = ZCC_FloatAuto; } +type_name1(X) ::= DOUBLE. { X = ZCC_Float64; } +type_name1(X) ::= STRING. { X = ZCC_String; } +type_name1(X) ::= VECTOR vector_size(A). { X = A; } +type_name1(X) ::= NAME. { X = ZCC_Name; } + +type_name(X) ::= type_name1(A). { - // FIXME - X = NULL; + NEW_AST_NODE(BasicType, type); + type->Type = A; + type->UserType = NULL; + X = type; +} +type_name(X) ::= IDENTIFIER(A). /* User-defined type (struct, enum, or class) */ +{ + NEW_AST_NODE(BasicType, type); + NEW_AST_NODE(ZCC_Identifier, id); + type->Type = ZCC_UserType; + type->UserType = id; + id->Id = A; + X = type; +} +type_name(X) ::= LBRACKET dottable_id(A) RBRACKET. +{ + NEW_AST_NODE(BasicType, type); + type->Type = ZCC_UserType; + type->UserType = A; + X = type; } -%type vector_size {unsigned int} - -vector_size ::= . -vector_size(X) ::= LT INTCONST(A) GT. { X = A.Int; } +/* Vectors can be 2, 3, or 4 entries long. Default is a 3D vector. + * (Well, actually, I'm not sure if 4D ones are going to happen + * straight away.) + */ +vector_size(X) ::= . { X = ZCC_Vector3; } +vector_size(X) ::= LT INTCONST(A) GT. +{ + if (A.Int >= 2 && A.Int <= 4) + { + X = ZCC_Vector2 + A.Int - 2; + } + else + { + X = ZCC_Vector3; + stat->sc.ScriptMessage("Invalid vector size %d\n", A.Int); + } +} /* Type names can also be used as identifiers in contexts where type names * are not normally allowed. */ @@ -401,15 +439,32 @@ vector_size(X) ::= LT INTCONST(A) GT. { X = A.Int; } %type type_list {ZCC_Type *} %type type_list_or_void {ZCC_Type *} %type type_or_array {ZCC_Type *} -%type class_restrictor {PClass *} +%type class_restrictor {ZCC_Identifier *} %type array_size{ZCC_Expression *} -aggregate_type ::= MAP LT type_or_array COMMA type_or_array GT. /* Hash table */ -aggregate_type ::= ARRAY LT type_or_array GT. /* TArray<type> */ -aggregate_type ::= CLASS class_restrictor. /* class<type> */ +aggregate_type(X) ::= MAP LT type_or_array(A) COMMA type_or_array(B) GT. /* Hash table */ +{ + NEW_AST_NODE(ZCC_MapType,map); + map->KeyType = A; + map->ValueType = B; + X = map; +} -class_restrictor ::= . -class_restrictor ::= LT IDENTIFIER GT. +aggregate_type(X) ::= ARRAY LT type_or_array(A) GT. /* TArray<type> */ +{ + NEW_AST_NODE(ZCC_DynArrayType,arr); + map->ElementType = A; + X = map; +} + +aggregate_type(X) ::= CLASS class_restrictor(A). /* class<type> */ +{ + NEW_AST_NODE(ZCC_ClassType,cls); + cls->Restriction = A; + X = cls; +} +class_restrictor(X) ::= . { X = NULL; } +class_restrictor(X) ::= LT dottable_id(A) GT. { X = A; } type(X) ::= type_name(A). { X = A; A->ArraySize = NULL; } type(X) ::= aggregate_type(A). { X = A; A->ArraySize = NULL; } @@ -451,17 +506,99 @@ array_size(X) ::= array_size(A) LBRACKET opt_expr(B) RBRACKET. 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. +%include +{ + struct VarOrFun + { + ZCC_VarName *VarNames; + ZCC_FuncParamDecl *FuncParams; + ENamedName FuncName; + int FuncFlags; + }; +} +%type variables_or_function {VarOrFun} -variables_or_function ::= IDENTIFIER LPAREN func_params RPAREN func_const opt_func_body. /* Function */ -variables_or_function ::= variable_list SEMICOLON. +/* Multiple type names are only valid for functions. */ +declarator(X) ::= decl_flags(A) type_list_or_void(B) variables_or_function(C). +{ + if (C.FuncParams == NULL && C.VarNames == NULL) + { // An error. A message was already printed. + X = NULL; + } + else if (C.FuncParams != NULL) + { // A function + NEW_AST_NODE(FuncDeclarator, decl); + decl->Type = B; + decl->Params = C.FuncParams; + decl->Name = C.FuncName; + decl->Flags = A | C.FuncFlags; + X = decl; + } + else if (B != NULL && B->Sibling == NULL) + { // A variable + NEW_AST_NODE(VarDeclarator, decl); + decl->Type = B; + decl->Names = C.VarNames; + decl->Flags = A; + X = decl; + } + else + { // An invalid + if (B == NULL) + { + sc.ScriptMessage("Variables may not be of type void.\n"); + } + else + { + sc.ScriptMessage("Variables may be of only one type.\n"); + } + X = NULL; + } +} +declarator_no_fun(X) ::= decl_flags(A) type(B) variable_list(C). +{ + NEW_AST_NODE(VarDeclarator, decl); + decl->Type = B; + decl->Names = C; + decl->Flags = A; + X = decl; +} + +// Need to split it up like this to avoid parsing conflicts. +variables_or_function(X) ::= IDENTIFIER(A) LPAREN func_params(B) RPAREN func_const(C) opt_func_body(D). /* Function */ +{ + VarOrFun fun; + + fun.VarNames = NULL; + fun.FuncParams = B; + fun.FuncFlags = C; + fun.FuncName = A.Name(); + fun.FuncBody = D; + X = fun; +} +variables_or_function(X) ::= variable_list(A) SEMICOLON. +{ + VarOrFun var; + + var.VarNames = A; + var.FuncParams = NULL; + var.FuncFlags = 0; + var.FuncName = NAME_None; + var.FuncBody = NULL; + X = var; +} variables_or_function ::= error SEMICOLON. +{ + VarOrFun bad; + bad.VarNames = NULL; + bad.FuncParams = NULL; + bad.FuncFlags = 0; + bad.FuncName = NAME_None; + bad.Func_Body = NULL; + X = bad; +} /*----- 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 *} @@ -499,8 +636,8 @@ decl_flags(X) ::= decl_flags(A) DEPRECATED. { X = A | ZCC_Deprecated; } func_const ::= . func_const ::= CONST. -opt_func_body ::= SEMICOLON. -opt_func_body ::= function_body. +opt_func_body(X) ::= SEMICOLON. { X = NULL; } +opt_func_body(X) ::= function_body(A). { X = A; } %type func_params {ZCC_FuncParamDecl *} %type func_param_list {ZCC_FuncParamDecl *} diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index f14261c28..c36c9127e 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -93,15 +93,26 @@ enum EZCCTreeNodeType AST_ConstantDef, }; -enum EZCCIntType +enum EZCCBuiltinType { - ZCCINT_SInt8, - ZCCINT_UInt8, - ZCCINT_SInt16, - ZCCINT_UInt16, - ZCCINT_SInt32, - ZCCINT_UInt32, - ZCCINT_Auto, // for enums, autoselect appropriately sized int + ZCC_SInt8, + ZCC_UInt8, + ZCC_SInt16, + ZCC_UInt16, + ZCC_SInt32, + ZCC_UInt32, + ZCC_IntAuto, // for enums, autoselect appropriately sized int + + ZCC_Bool, + ZCC_Float32, + ZCC_Float64, + ZCC_FloatAuto, // 32-bit in structs/classes, 64-bit everywhere else + ZCC_String, + ZCC_Vector2, + ZCC_Vector3, + ZCC_Vector4, + ZCC_Name, + ZCC_UserType, }; enum EZCCExprType @@ -293,8 +304,8 @@ struct ZCC_Type : ZCC_TreeNode struct ZCC_BasicType : ZCC_Type { - PType *Type; - ENamedName TypeName; + EZCCBuiltinType Type; + ZCC_Identifier *UserType; }; struct ZCC_MapType : ZCC_Type @@ -310,7 +321,24 @@ struct ZCC_DynArrayType : ZCC_Type struct ZCC_ClassType : ZCC_Type { - ENamedName Restriction; + ZCC_Identifier *Restriction; +}; + +// A variable in a class or struct. +struct ZCC_VarDeclarator : ZCC_TreeNode +{ + ZCC_Type *Type; + ZCC_VarName *Names; + int Flags; +}; + +// A function in a class. +struct ZCC_FuncDeclarator : ZCC_TreeNode +{ + ZCC_Type *Type; + ZCC_FuncParamDecl *Params; + ENamedName Name; + int Flags; }; struct ZCC_ExprID : ZCC_Expression From 4b8900816bef74ccb5980377b827b951772964c4 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 8 Sep 2010 04:32:31 +0000 Subject: [PATCH 043/232] - Make the ZCC parser compilable again. Does every rule in the grammar that needs to appear in the AST do so now? That would sure be nice. SVN r2715 (scripting) --- src/zscript/zcc-parse.lemon | 69 +++++++++++++++++++------------------ src/zscript/zcc_parser.h | 42 ++++++++++++---------- 2 files changed, 59 insertions(+), 52 deletions(-) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index 2f8c225ae..8f029b83f 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -101,7 +101,8 @@ opt_expr(X) ::= expr(A). %type class_definition{ZCC_Class *} %type class_head{ZCC_Class *} -%type class_innards{ZCC_Class *} +%type class_innards{ZCC_TreeNode *} +%type class_member{ZCC_TreeNode *} %type class_body{ZCC_TreeNode *} class_definition(X) ::= class_head(A) class_body(B). @@ -125,7 +126,7 @@ class_ancestry(X) ::= . { X = NULL; } class_ancestry(X) ::= COLON dottable_id(A). { X = A; } %type class_flags{ClassFlagsBlock} -%include{ +%include { struct ClassFlagsBlock { VM_UWORD Flags; ZCC_Identifier *Replaces; @@ -165,30 +166,29 @@ dottable_id(X) ::= dottable_id(A) DOT IDENTIFIER(B). // * constants // * defaults -class_body ::= SEMICOLON class_innards EOF. -class_body ::= LBRACE class_innards RBRACE. +class_body(X) ::= SEMICOLON class_innards(A) EOF. { X = A; } +class_body(X) ::= LBRACE class_innards(A) RBRACE. { X = A; } -class_innards ::= . -class_innards ::= class_innards class_member. +class_innards(X) ::= . { X = NULL; } +class_innards(X) ::= class_innards(A) class_member(B). { SAFE_APPEND(A,B); X = A; } %type struct_def{ZCC_Struct *} %type enum_def {ZCC_Enum *} %type states_def {ZCC_States *} %type const_def {ZCC_ConstantDef *} -class_member ::= declarator. -class_member ::= enum_def. -class_member ::= struct_def. -class_member ::= states_def. -class_member ::= default_def. -class_member ::= const_def. +class_member(X) ::= declarator(A). { X = A; } +class_member(X) ::= enum_def(A). { X = A; } +class_member(X) ::= struct_def(A). { X = A; } +class_member(X) ::= states_def(A). { X = A; } +class_member(X) ::= default_def(A). { X = A; } +class_member(X) ::= const_def(A). { X = A; } /*----- Struct Definition -----*/ /* Structs can define variables and enums. */ %type struct_body{ZCC_TreeNode *} %type struct_member{ZCC_TreeNode *} -%type declarator_no_fun {ZCC_TreeNode *} struct_def(X) ::= STRUCT IDENTIFIER(A) LBRACE struct_body(B) RBRACE opt_semicolon. { @@ -222,7 +222,7 @@ enum_def(X) ::= ENUM IDENTIFIER(A) enum_type(B) LBRACE enum_list(C) opt_comma RB X = def; } -enum_type(X) ::= . { X = ZCCINT_Auto; } +enum_type(X) ::= . { X = ZCC_IntAuto; } enum_type(X) ::= COLON int_type(A). { X = A; } enum_list(X) ::= error. { X = NULL; } @@ -255,10 +255,8 @@ enumerator(X) ::= IDENTIFIER(A) EQ expr(B). /* Expression must be constant. */ %type state_action {ZCC_TreeNode *} %type state_call {ZCC_ExprFuncCall *} -%include -{ - struct StateOpts - { +%include { + struct StateOpts { ZCC_Expression *Offset; bool Bright; }; @@ -363,7 +361,8 @@ state_call(X) ::= IDENTIFIER(A) func_expr_list(B). } /* Definition of a default class instance. */ -default_def ::= DEFAULT compound_statement. +%type default_def {ZCC_CompoundStmt *} +default_def(X) ::= DEFAULT compound_statement(A). { X = A; } /* Type names */ %type int_type {EZCCBuiltinType} @@ -396,10 +395,10 @@ type_name(X) ::= type_name1(A). type_name(X) ::= IDENTIFIER(A). /* User-defined type (struct, enum, or class) */ { NEW_AST_NODE(BasicType, type); - NEW_AST_NODE(ZCC_Identifier, id); + NEW_AST_NODE(Identifier, id); type->Type = ZCC_UserType; type->UserType = id; - id->Id = A; + id->Id = A.Name(); X = type; } type_name(X) ::= LBRACKET dottable_id(A) RBRACKET. @@ -419,7 +418,7 @@ vector_size(X) ::= LT INTCONST(A) GT. { if (A.Int >= 2 && A.Int <= 4) { - X = ZCC_Vector2 + A.Int - 2; + X = EZCCBuiltinType(ZCC_Vector2 + A.Int - 2); } else { @@ -444,7 +443,7 @@ vector_size(X) ::= LT INTCONST(A) GT. aggregate_type(X) ::= MAP LT type_or_array(A) COMMA type_or_array(B) GT. /* Hash table */ { - NEW_AST_NODE(ZCC_MapType,map); + NEW_AST_NODE(MapType,map); map->KeyType = A; map->ValueType = B; X = map; @@ -452,14 +451,14 @@ aggregate_type(X) ::= MAP LT type_or_array(A) COMMA type_or_array(B) GT. /* Hash aggregate_type(X) ::= ARRAY LT type_or_array(A) GT. /* TArray<type> */ { - NEW_AST_NODE(ZCC_DynArrayType,arr); - map->ElementType = A; - X = map; + NEW_AST_NODE(DynArrayType,arr); + arr->ElementType = A; + X = arr; } aggregate_type(X) ::= CLASS class_restrictor(A). /* class<type> */ { - NEW_AST_NODE(ZCC_ClassType,cls); + NEW_AST_NODE(ClassType,cls); cls->Restriction = A; X = cls; } @@ -512,6 +511,7 @@ array_size(X) ::= array_size(A) LBRACKET opt_expr(B) RBRACKET. { ZCC_VarName *VarNames; ZCC_FuncParamDecl *FuncParams; + ZCC_CompoundStmt *FuncBody; ENamedName FuncName; int FuncFlags; }; @@ -534,7 +534,7 @@ declarator(X) ::= decl_flags(A) type_list_or_void(B) variables_or_function(C). decl->Flags = A | C.FuncFlags; X = decl; } - else if (B != NULL && B->Sibling == NULL) + else if (B != NULL && B->SiblingNext == B) { // A variable NEW_AST_NODE(VarDeclarator, decl); decl->Type = B; @@ -546,11 +546,11 @@ declarator(X) ::= decl_flags(A) type_list_or_void(B) variables_or_function(C). { // An invalid if (B == NULL) { - sc.ScriptMessage("Variables may not be of type void.\n"); + stat->sc.ScriptMessage("Variables may not be of type void.\n"); } else { - sc.ScriptMessage("Variables may be of only one type.\n"); + stat->sc.ScriptMessage("Variables may be of only one type.\n"); } X = NULL; } @@ -587,14 +587,14 @@ variables_or_function(X) ::= variable_list(A) SEMICOLON. var.FuncBody = NULL; X = var; } -variables_or_function ::= error SEMICOLON. +variables_or_function(X) ::= error SEMICOLON. { VarOrFun bad; bad.VarNames = NULL; bad.FuncParams = NULL; bad.FuncFlags = 0; bad.FuncName = NAME_None; - bad.Func_Body = NULL; + bad.FuncBody = NULL; X = bad; } @@ -603,6 +603,7 @@ variables_or_function ::= error SEMICOLON. %type variable_name{ZCC_VarName *} %type variable_list{ZCC_VarName *} %type decl_flags{int} +%type func_const{int} variable_name(X) ::= IDENTIFIER(A). { @@ -633,8 +634,8 @@ decl_flags(X) ::= decl_flags(A) ACTION. { X = A | ZCC_Action; } decl_flags(X) ::= decl_flags(A) READONLY. { X = A | ZCC_ReadOnly; } decl_flags(X) ::= decl_flags(A) DEPRECATED. { X = A | ZCC_Deprecated; } -func_const ::= . -func_const ::= CONST. +func_const(X) ::= . { X = 0; } +func_const(X) ::= CONST. { X = ZCC_FuncConst; } opt_func_body(X) ::= SEMICOLON. { X = NULL; } opt_func_body(X) ::= function_body(A). { X = A; } diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index c36c9127e..f0b51e1aa 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -31,6 +31,7 @@ enum ZCC_Action = 1 << 7, ZCC_Deprecated = 1 << 8, ZCC_ReadOnly = 1 << 9, + ZCC_FuncConst = 1 << 10, }; // Function parameter modifiers @@ -91,6 +92,9 @@ enum EZCCTreeNodeType AST_LocalVarStmt, AST_FuncParamDecl, AST_ConstantDef, + AST_Declarator, + AST_VarDeclarator, + AST_FuncDeclarator, }; enum EZCCBuiltinType @@ -232,7 +236,7 @@ struct ZCC_Struct : ZCC_TreeNode struct ZCC_Enum : ZCC_TreeNode { ENamedName EnumName; - EZCCIntType EnumType; + EZCCBuiltinType EnumType; struct ZCC_EnumNode *Elements; }; @@ -324,23 +328,6 @@ struct ZCC_ClassType : ZCC_Type ZCC_Identifier *Restriction; }; -// A variable in a class or struct. -struct ZCC_VarDeclarator : ZCC_TreeNode -{ - ZCC_Type *Type; - ZCC_VarName *Names; - int Flags; -}; - -// A function in a class. -struct ZCC_FuncDeclarator : ZCC_TreeNode -{ - ZCC_Type *Type; - ZCC_FuncParamDecl *Params; - ENamedName Name; - int Flags; -}; - struct ZCC_ExprID : ZCC_Expression { ENamedName Identifier; @@ -481,3 +468,22 @@ struct ZCC_ConstantDef : ZCC_TreeNode ENamedName Name; ZCC_Expression *Value; }; + +struct ZCC_Declarator : ZCC_TreeNode +{ + ZCC_Type *Type; + int Flags; +}; + +// A variable in a class or struct. +struct ZCC_VarDeclarator : ZCC_Declarator +{ + ZCC_VarName *Names; +}; + +// A function in a class. +struct ZCC_FuncDeclarator : ZCC_Declarator +{ + ZCC_FuncParamDecl *Params; + ENamedName Name; +}; From 7e60ac1fb84dc566a19f638d83be375679d40369 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Thu, 16 Sep 2010 03:24:04 +0000 Subject: [PATCH 044/232] - Fixed: FArchive::m_NameHash was never initialized. SVN r2791 (scripting) --- src/farchive.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/farchive.cpp b/src/farchive.cpp index 694736583..4c51b7b29 100644 --- a/src/farchive.cpp +++ b/src/farchive.cpp @@ -657,6 +657,10 @@ void FArchive::AttachToFile (FFile &file) ObjectToArchive.Clear(); ArchiveToObject.Clear(); + memset(m_NameHash, 0xFF, sizeof(m_NameHash)); + m_Names.Clear(); + m_NameStorage.Clear(); + m_NumSprites = 0; m_SpriteMap = new int[sprites.Size()]; for (size_t s = 0; s < sprites.Size(); ++s) From bee4c3e760084eb8cf79551bba985edb9a162995 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sun, 31 Oct 2010 04:36:00 +0000 Subject: [PATCH 045/232] - Added functions for converting the AST to text. This is not hooked in anywhere yet, since the parser currently just throws the AST away. SVN r2969 (scripting) --- src/zscript/ast.cpp | 610 +++++++++++++++++++++++++++++++++++++++ src/zscript/zcc_parser.h | 10 +- zdoom.vcproj | 4 + 3 files changed, 623 insertions(+), 1 deletion(-) create mode 100644 src/zscript/ast.cpp diff --git a/src/zscript/ast.cpp b/src/zscript/ast.cpp new file mode 100644 index 000000000..5757e4b04 --- /dev/null +++ b/src/zscript/ast.cpp @@ -0,0 +1,610 @@ +#include "dobject.h" +#include "sc_man.h" +#include "memarena.h" +#include "zcc_parser.h" +#include "zcc-parse.h" + +extern void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FString &, ZCC_TreeNode *); + +static const char *BuiltInTypeNames[] = +{ + "sint8", "uint8", + "sint16", "uint16", + "sint32", "uint32", + "intauto", + + "bool", + "float32", "float64", "floatauto", + "string", + "vector2", + "vector3", + "vector4", + "name", + "usertype" +}; + +static void PrintNode(FString &out, ZCC_TreeNode *node) +{ + assert(TreeNodePrinter[NUM_AST_NODE_TYPES-1] != NULL); + if (node->NodeType >= 0 && node->NodeType < NUM_AST_NODE_TYPES) + { + TreeNodePrinter[node->NodeType](out, node); + } + else + { + out.AppendFormat("(unknown-node-type-%d)", node->NodeType); + } +} + +static void PrintNodes(FString &out, ZCC_TreeNode *node, char addchar=' ') +{ + ZCC_TreeNode *p; + + if (node == NULL) + { + out << "nil"; + } + else + { + out << '('; + p = node; + do + { + PrintNode(out, p); + p = p->SiblingNext; + if (p != node) + { + out << ' '; + } + } while (p != node); + out << ')'; + } + if (addchar != '\0') + { + out << addchar; + } +} + +static void PrintBuiltInType(FString &out, EZCCBuiltinType type, bool addspace) +{ + assert(ZCC_NUM_BUILT_IN_TYPES == countof(BuiltInTypeNames)); + if (unsigned(type) >= unsigned(ZCC_NUM_BUILT_IN_TYPES)) + { + out.AppendFormat("bad-type-%u", type); + } + else + { + out << BuiltInTypeNames[type]; + } + if (addspace) + { + out << ' '; + } +} + +static void PrintIdentifier(FString &out, ZCC_TreeNode *node) +{ + ZCC_Identifier *inode = (ZCC_Identifier *)node; + out.AppendFormat("(identifier '%s')", FName(inode->Id).GetChars()); +} + +static void PrintStringConst(FString &out, FString str) +{ + out << '"'; + for (size_t i = 0; i < str.Len(); ++i) + { + if (str[i] == '"') + { + out << "\""; + } + else if (str[i] == '\\') + { + out << "\\\\"; + } + else if (str[i] >= 32) + { + out << str[i]; + } + else + { + out.AppendFormat("\\x%02X", str[i]); + } + } +} + +static void PrintClass(FString &out, ZCC_TreeNode *node) +{ + ZCC_Class *cnode = (ZCC_Class *)node; + out << "(class "; + PrintNodes(out, cnode->ClassName); + PrintNodes(out, cnode->ParentName); + PrintNodes(out, cnode->Replaces); + out.AppendFormat("%08x ", cnode->Flags); + PrintNodes(out, cnode->Body, ')'); +} + +static void PrintStruct(FString &out, ZCC_TreeNode *node) +{ + ZCC_Struct *snode = (ZCC_Struct *)node; + out.AppendFormat("(struct '%s' ", FName(snode->StructName).GetChars()); + PrintNodes(out, snode->Body, ')'); +} + +static void PrintEnum(FString &out, ZCC_TreeNode *node) +{ + ZCC_Enum *enode = (ZCC_Enum *)node; + out.AppendFormat("(enum '%s' ", FName(enode->EnumName).GetChars()); + PrintBuiltInType(out, enode->EnumType, true); + PrintNodes(out, enode->Elements, ')'); +} + +static void PrintEnumNode(FString &out, ZCC_TreeNode *node) +{ + ZCC_EnumNode *enode = (ZCC_EnumNode *)node; + out.AppendFormat("(enum-node '%s' ", FName(enode->ElemName)); + PrintNodes(out, enode->ElemValue, ')'); +} + +static void PrintStates(FString &out, ZCC_TreeNode *node) +{ + ZCC_States *snode = (ZCC_States *)node; + out << "(states "; + PrintNodes(out, snode->Body, ')'); +} + +static void PrintStatePart(FString &out, ZCC_TreeNode *node) +{ + out << "(state-part)"; +} + +static void PrintStateLabel(FString &out, ZCC_TreeNode *node) +{ + ZCC_StateLabel *snode = (ZCC_StateLabel *)node; + out.AppendFormat("(state-label '%s')", FName(snode->Label).GetChars()); +} + +static void PrintStateStop(FString &out, ZCC_TreeNode *node) +{ + out << "(state-stop)"; +} + +static void PrintStateWait(FString &out, ZCC_TreeNode *node) +{ + out << "(state-wait)"; +} + +static void PrintStateFail(FString &out, ZCC_TreeNode *node) +{ + out << "(state-fail)"; +} + +static void PrintStateLoop(FString &out, ZCC_TreeNode *node) +{ + out << "(state-loop)"; +} + +static void PrintStateGoto(FString &out, ZCC_TreeNode *node) +{ + ZCC_StateGoto *snode = (ZCC_StateGoto *)node; + out << "(state-goto "; + PrintNodes(out, snode->Label); + PrintNodes(out, snode->Offset, ')'); +} + +static void PrintStateLine(FString &out, ZCC_TreeNode *node) +{ + ZCC_StateLine *snode = (ZCC_StateLine *)node; + out.AppendFormat("(state-line %c%c%c%c %s %s ", + snode->Sprite[0], snode->Sprite[1], snode->Sprite[2], snode->Sprite[3], + snode->bBright ? "bright " : "", + snode->Frames->GetChars()); + PrintNodes(out, snode->Offset); + PrintNodes(out, snode->Action, ')'); +} + +static void PrintVarName(FString &out, ZCC_TreeNode *node) +{ + ZCC_VarName *vnode = (ZCC_VarName *)node; + out.AppendFormat("(var-name '%s')", FName(vnode->Name).GetChars()); +} + +static void PrintType(FString &out, ZCC_TreeNode *node) +{ + ZCC_Type *tnode = (ZCC_Type *)node; + out << "(bad-type "; + PrintNodes(out, tnode->ArraySize, ')'); +} + +static void PrintBasicType(FString &out, ZCC_TreeNode *node) +{ + ZCC_BasicType *tnode = (ZCC_BasicType *)node; + out << "(basic-type "; + PrintNodes(out, tnode->ArraySize); + PrintBuiltInType(out, tnode->Type, true); + PrintNodes(out, tnode->UserType, ')'); +} + +static void PrintMapType(FString &out, ZCC_TreeNode *node) +{ + ZCC_MapType *tnode = (ZCC_MapType *)node; + out << "(map-type "; + PrintNodes(out, tnode->ArraySize); + PrintNodes(out, tnode->KeyType); + PrintNodes(out, tnode->ValueType, ')'); +} + +static void PrintDynArrayType(FString &out, ZCC_TreeNode *node) +{ + ZCC_DynArrayType *tnode = (ZCC_DynArrayType *)node; + out << "(dyn-array-type "; + PrintNodes(out, tnode->ArraySize); + PrintNodes(out, tnode->ElementType, ')'); +} + +static void PrintClassType(FString &out, ZCC_TreeNode *node) +{ + ZCC_ClassType *tnode = (ZCC_ClassType *)node; + out << "(class-type "; + PrintNodes(out, tnode->ArraySize); + PrintNodes(out, tnode->Restriction, ')'); +} + +static void PrintExprType(FString &out, EZCCExprType type) +{ + static const char *const types[] = + { + "nil ", + "id ", + "super ", + "self ", + "string-const ", + "int-const ", + "uint-const ", + "float-const ", + "func-call ", + "array-access ", + "member-access ", + "post-inc ", + "post-dec ", + "pre-inc ", + "pre-dec ", + "negate ", + "anti-negate ", + "bit-not ", + "bool-not ", + "size-of ", + "align-of ", + "add ", + "sub ", + "mul ", + "div ", + "mod ", + "pow ", + "cross-product ", + "dot-product ", + "left-shift ", + "right-shift ", + "concat ", + "lt ", + "gt ", + "lteq ", + "gteq ", + "ltgteq ", + "is ", + "eqeq ", + "neq ", + "apreq ", + "bit-and ", + "bit-or ", + "bit-xor ", + "bool-and ", + "bool-or ", + "scope ", + "trinary ", + }; + assert(countof(types) == PEX_COUNT_OF); + + if (unsigned(type) < countof(types)) + { + out << types[type]; + } + else + { + out.AppendFormat("bad-pex-%u ", type); + } +} + +static void PrintExpression(FString &out, ZCC_TreeNode *node) +{ + ZCC_Expression *enode = (ZCC_Expression *)node; + out << "(expr-"; + PrintExprType(out, enode->Operation); + out << ')'; +} + +static void PrintExprID(FString &out, ZCC_TreeNode *node) +{ + ZCC_ExprID *enode = (ZCC_ExprID *)node; + assert(enode->Operation == PEX_ID); + out.AppendFormat("(expr-id '%s')", FName(enode->Identifier).GetChars()); +} + +static void PrintExprString(FString &out, ZCC_TreeNode *node) +{ + ZCC_ExprString *enode = (ZCC_ExprString *)node; + assert(enode->Operation == PEX_StringConst); + out.AppendFormat("(expr-string-const "); + PrintStringConst(out, *enode->Value); + out << ')'; +} + +static void PrintExprInt(FString &out, ZCC_TreeNode *node) +{ + ZCC_ExprInt *enode = (ZCC_ExprInt *)node; + assert(enode->Operation == PEX_IntConst || enode->Operation == PEX_UIntConst); + out << "(expr-"; + PrintExprType(out, enode->Operation); + out.AppendFormat("%d)", enode->Value); +} + +static void PrintExprFloat(FString &out, ZCC_TreeNode *node) +{ + ZCC_ExprFloat *enode = (ZCC_ExprFloat *)node; + assert(enode->Operation == PEX_FloatConst); + out.AppendFormat("(expr-float-const %g)", enode->Value); +} + +static void PrintExprFuncCall(FString &out, ZCC_TreeNode *node) +{ + ZCC_ExprFuncCall *enode = (ZCC_ExprFuncCall *)node; + assert(enode->Operation == PEX_FuncCall); + out << "(expr-func-call "; + PrintNodes(out, enode->Function); + PrintNodes(out, enode->Parameters, ')'); +} + +static void PrintExprMemberAccess(FString &out, ZCC_TreeNode *node) +{ + ZCC_ExprMemberAccess *enode = (ZCC_ExprMemberAccess *)node; + assert(enode->Operation == PEX_MemberAccess); + out << "(expr-member-access "; + PrintNodes(out, enode->Left); + out.AppendFormat("'%s')", FName(enode->Right).GetChars()); +} + +static void PrintExprUnary(FString &out, ZCC_TreeNode *node) +{ + ZCC_ExprUnary *enode = (ZCC_ExprUnary *)node; + out << "(expr-"; + PrintExprType(out, enode->Operation); + PrintNodes(out, enode->Operand, ')'); +} + +static void PrintExprBinary(FString &out, ZCC_TreeNode *node) +{ + ZCC_ExprBinary *enode = (ZCC_ExprBinary *)node; + out << "(expr-"; + PrintExprType(out, enode->Operation); + PrintNodes(out, enode->Left); + PrintNodes(out, enode->Right, ')'); +} + +static void PrintExprTrinary(FString &out, ZCC_TreeNode *node) +{ + ZCC_ExprTrinary *enode = (ZCC_ExprTrinary *)node; + out << "(expr-"; + PrintExprType(out, enode->Operation); + PrintNodes(out, enode->Test); + PrintNodes(out, enode->Left); + PrintNodes(out, enode->Right, ')'); +} + +static void PrintFuncParam(FString &out, ZCC_TreeNode *node) +{ + ZCC_FuncParm *pnode = (ZCC_FuncParm *)node; + out.AppendFormat("(func-parm %s ", FName(pnode->Label).GetChars());; + PrintNodes(out, pnode->Value, ')'); +} + +static void PrintStatement(FString &out, ZCC_TreeNode *node) +{ + out << "(statement)"; +} + +static void PrintCompoundStmt(FString &out, ZCC_TreeNode *node) +{ + ZCC_CompoundStmt *snode = (ZCC_CompoundStmt *)node; + out << "(compound-stmt "; + PrintNodes(out, snode->Content, ')'); +} + +static void PrintContinueStmt(FString &out, ZCC_TreeNode *node) +{ + out << "(continue-stmt)"; +} + +static void PrintBreakStmt(FString &out, ZCC_TreeNode *node) +{ + out << "(break-stmt)"; +} + +static void PrintReturnStmt(FString &out, ZCC_TreeNode *node) +{ + ZCC_ReturnStmt *snode = (ZCC_ReturnStmt *)node; + out << "(return-stmt "; + PrintNodes(out, snode->Values, ')'); +} + +static void PrintExpressionStmt(FString &out, ZCC_TreeNode *node) +{ + ZCC_ExpressionStmt *snode = (ZCC_ExpressionStmt *)node; + out << "(expression-stmt "; + PrintNodes(out, snode->Expression, ')'); +} + +static void PrintIterationStmt(FString &out, ZCC_TreeNode *node) +{ + ZCC_IterationStmt *snode = (ZCC_IterationStmt *)node; + out << "(iteration-stmt "; + out << (snode->CheckAt == ZCC_IterationStmt::Start) ? "start " : "end "; + PrintNodes(out, snode->LoopCondition); + PrintNodes(out, snode->LoopBumper); + PrintNodes(out, snode->LoopStatement, true); +} + +static void PrintIfStmt(FString &out, ZCC_TreeNode *node) +{ + ZCC_IfStmt *snode = (ZCC_IfStmt *)node; + out << "(if-stmt "; + PrintNodes(out, snode->Condition); + PrintNodes(out, snode->TruePath); + PrintNodes(out, snode->FalsePath, ')'); +} + +static void PrintSwitchStmt(FString &out, ZCC_TreeNode *node) +{ + ZCC_SwitchStmt *snode = (ZCC_SwitchStmt *)node; + out << "(switch-stmt "; + PrintNodes(out, snode->Condition); + PrintNodes(out, snode->Content, ')'); +} + +static void PrintCaseStmt(FString &out, ZCC_TreeNode *node) +{ + ZCC_CaseStmt *snode = (ZCC_CaseStmt *)node; + out << "(case-stmt "; + PrintNodes(out, snode->Condition, ')'); +} + +static void PrintAssignStmt(FString &out, ZCC_TreeNode *node) +{ + ZCC_AssignStmt *snode = (ZCC_AssignStmt *)node; + out << "(assign-stmt "; + switch (snode->AssignOp) + { + case ZCC_EQ: out << "= "; break; + case ZCC_MULEQ: out << "*= "; break; + case ZCC_DIVEQ: out << "/= "; break; + case ZCC_MODEQ: out << "%= "; break; + case ZCC_ADDEQ: out << "+= "; break; + case ZCC_SUBEQ: out << "-= "; break; + case ZCC_LSHEQ: out << "<<= "; break; + case ZCC_RSHEQ: out << ">>= "; break; + case ZCC_ANDEQ: out << "&= "; break; + case ZCC_OREQ: out << "|= "; break; + case ZCC_XOREQ: out << "^= "; break; + default: + out.AppendFormat("assign-op-%d ", snode->AssignOp); + } + PrintNodes(out, snode->Dests); + PrintNodes(out, snode->Sources, ')'); +} + +static void PrintLocalVarStmt(FString &out, ZCC_TreeNode *node) +{ + ZCC_LocalVarStmt *snode = (ZCC_LocalVarStmt *)node; + out << "(local-var-stmt "; + PrintNodes(out, snode->Type); + PrintNodes(out, snode->Vars); + PrintNodes(out, snode->Inits, ')'); +} + +static void PrintFuncParamDecl(FString &out, ZCC_TreeNode *node) +{ + ZCC_FuncParamDecl *dnode = (ZCC_FuncParamDecl *)node; + out << "(func-param-decl "; + PrintNodes(out, dnode->Type); + out.AppendFormat("%s %x)", FName(dnode->Name).GetChars(), dnode->Flags); +} + +static void PrintConstantDef(FString &out, ZCC_TreeNode *node) +{ + ZCC_ConstantDef *dnode = (ZCC_ConstantDef *)node; + out.AppendFormat("(constant-def %s ", FName(dnode->Name).GetChars()); + PrintNodes(out, dnode->Value, ')'); +} + +static void PrintDeclarator(FString &out, ZCC_TreeNode *node) +{ + ZCC_Declarator *dnode = (ZCC_Declarator *)node; + out << "(declarator "; + PrintNodes(out, dnode->Type); + out.AppendFormat("%x)", dnode->Flags); +} + +static void PrintVarDeclarator(FString &out, ZCC_TreeNode *node) +{ + ZCC_VarDeclarator *dnode = (ZCC_VarDeclarator *)node; + out << "(var-declarator "; + PrintNodes(out, dnode->Type); + out.AppendFormat("%x ", dnode->Flags); + PrintNodes(out, dnode->Names, ')'); +} + +static void PrintFuncDeclarator(FString &out, ZCC_TreeNode *node) +{ + ZCC_FuncDeclarator *dnode = (ZCC_FuncDeclarator *)node; + out << "(func-declarator "; + PrintNodes(out, dnode->Type); + out.AppendFormat("%x %s ", dnode->Flags, FName(dnode->Name).GetChars()); + PrintNodes(out, dnode->Params, ')'); +} + +void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FString &, ZCC_TreeNode *) = +{ + PrintIdentifier, + PrintClass, + PrintStruct, + PrintEnum, + PrintEnumNode, + PrintStates, + PrintStatePart, + PrintStateLabel, + PrintStateStop, + PrintStateWait, + PrintStateFail, + PrintStateLoop, + PrintStateGoto, + PrintStateLine, + PrintVarName, + PrintType, + PrintBasicType, + PrintMapType, + PrintDynArrayType, + PrintClassType, + PrintExpression, + PrintExprID, + PrintExprString, + PrintExprInt, + PrintExprFloat, + PrintExprFuncCall, + PrintExprMemberAccess, + PrintExprUnary, + PrintExprBinary, + PrintExprTrinary, + PrintFuncParam, + PrintStatement, + PrintCompoundStmt, + PrintContinueStmt, + PrintBreakStmt, + PrintReturnStmt, + PrintExpressionStmt, + PrintIterationStmt, + PrintIfStmt, + PrintSwitchStmt, + PrintCaseStmt, + PrintAssignStmt, + PrintLocalVarStmt, + PrintFuncParamDecl, + PrintConstantDef, + PrintDeclarator, + PrintVarDeclarator, + PrintFuncDeclarator +}; + +FString ZCC_PrintAST(ZCC_TreeNode *root) +{ + FString out; + PrintNodes(out, root, '\0'); + return out; +} diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index f0b51e1aa..5256e4637 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -95,6 +95,8 @@ enum EZCCTreeNodeType AST_Declarator, AST_VarDeclarator, AST_FuncDeclarator, + + NUM_AST_NODE_TYPES }; enum EZCCBuiltinType @@ -117,6 +119,8 @@ enum EZCCBuiltinType ZCC_Vector4, ZCC_Name, ZCC_UserType, + + ZCC_NUM_BUILT_IN_TYPES }; enum EZCCExprType @@ -176,7 +180,9 @@ enum EZCCExprType PEX_Scope, - PEX_Trinary + PEX_Trinary, + + PEX_COUNT_OF }; struct ZCC_TreeNode @@ -487,3 +493,5 @@ struct ZCC_FuncDeclarator : ZCC_Declarator ZCC_FuncParamDecl *Params; ENamedName Name; }; + +FString ZCC_PrintAST(ZCC_TreeNode *root); diff --git a/zdoom.vcproj b/zdoom.vcproj index 4dbee7678..89a6d7c05 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -6469,6 +6469,10 @@ <Filter Name="ZScript" > + <File + RelativePath=".\src\zscript\ast.cpp" + > + </File> <File RelativePath=".\src\zscript\vm.h" > From 615f49572b93b833534edc2219957199e045382c Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 14 Jul 2012 03:10:47 +0000 Subject: [PATCH 046/232] - Fix assertion failure when using FRandom. SVN r3759 (scripting) --- src/thingdef/thingdef_expression.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 1b8d0c4d5..9f17e5678 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -2420,8 +2420,8 @@ FxExpression *FxRandom::Resolve(FCompileContext &ctx) RESOLVE(min, ctx); RESOLVE(max, ctx); ABORT(min && max); - assert(min->ValueType == VAL_Int); - assert(max->ValueType == VAL_Int); + assert(min->ValueType == ValueType.Type); + assert(max->ValueType == ValueType.Type); } return this; }; From 136a2cd05a14db445545bc6bd78e885ecbc251d6 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 14 Jul 2012 03:56:56 +0000 Subject: [PATCH 047/232] - Since the scripting branch relies heavily on the garbage collector to clean up everything, move the final GC back to after the type system has been shut down. SVN r3760 (scripting) --- src/d_main.cpp | 33 +++++++++++++++++---------------- src/dobject.cpp | 2 +- src/win32/i_main.cpp | 2 +- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 603e66842..ee46a894d 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1805,6 +1805,22 @@ static void SetMapxxFlag() if (lump_name >= 0 || lump_wad >= 0 || lump_map >= 0) gameinfo.flags |= GI_MAPxx; } +//========================================================================== +// +// FinalGC +// +// If this doesn't free everything, the debug CRT will let us know. +// +//========================================================================== + +static void FinalGC() +{ + Args = NULL; + GC::FinalGC = true; + GC::FullGC(); + GC::DelSoftRootHead(); // the soft root head will not be collected by a GC so we have to do it explicitly +} + //========================================================================== // // Initialize @@ -1833,6 +1849,7 @@ static void D_DoomInit() // Check response files before coalescing file parameters. M_FindResponseFile (); + atterm(FinalGC); PClass::StaticInit(); PType::StaticInit(); @@ -2059,21 +2076,6 @@ static void CheckCmdLine() } } -//========================================================================== -// -// FinalGC -// -// If this doesn't free everything, the debug CRT will let us know. -// -//========================================================================== - -static void FinalGC() -{ - Args = NULL; - GC::FullGC(); - GC::DelSoftRootHead(); // the soft root head will not be collected by a GC so we have to do it explicitly -} - //========================================================================== // // D_DoomMain @@ -2091,7 +2093,6 @@ void D_DoomMain (void) int argcount; D_DoomInit(); - atterm(FinalGC); // [RH] Make sure zdoom.pk3 is always loaded, // as it contains magic stuff we need. diff --git a/src/dobject.cpp b/src/dobject.cpp index d36e1baf4..8e209e640 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -257,7 +257,7 @@ DObject::DObject (PClass *inClass) DObject::~DObject () { - if (!(ObjectFlags & OF_Cleanup)) + if (!(ObjectFlags & OF_Cleanup) && !PClass::bShutdown) { DObject **probe; PClass *type = GetClass(); diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp index 4079fcae7..2369d4bde 100644 --- a/src/win32/i_main.cpp +++ b/src/win32/i_main.cpp @@ -1285,7 +1285,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE nothing, LPSTR cmdline, int n _CrtSetDbgFlag (_CrtSetDbgFlag(0) | _CRTDBG_LEAK_CHECK_DF); // Use this to break at a specific allocation number. - //_crtBreakAlloc = 77624; + //_crtBreakAlloc = 18800; #endif DoMain (hInstance); From 644f0c0e05e820a1777dc429a514312542dbb125 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 17 Jul 2012 03:35:03 +0000 Subject: [PATCH 048/232] - Add a name to VMFunction so that the disassembly can be more informative. SVN r3768 (scripting) --- src/namedef.h | 9 ++++++- src/thingdef/thingdef.cpp | 5 ++++ src/thingdef/thingdef_data.cpp | 2 +- src/thingdef/thingdef_expression.cpp | 36 ++++++++++++++-------------- src/zscript/vm.h | 9 +++++-- src/zscript/vmdisasm.cpp | 12 ++++++++++ src/zscript/vmframe.cpp | 3 ++- 7 files changed, 53 insertions(+), 23 deletions(-) diff --git a/src/namedef.h b/src/namedef.h index a46863ce3..95a5aca9a 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -549,4 +549,11 @@ xx(Inter_Strife_Bad) xx(Inter_Strife_Lose) xx(Inter_Strife_MAP03) xx(Inter_Strife_MAP10) -xx(Multiplayer) \ No newline at end of file +xx(Multiplayer) + +// Decorate compatibility functions +xx(DecoRandom) +xx(DecoFRandom) +xx(DecoCallLineSpecial) +xx(DecoNameToClass) +xx(DecoFindMultiNameState) diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index b4bf28ccc..3b68851c8 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -264,6 +264,7 @@ static void FinishThingdef() { int errorcount = StateParams.ResolveAll(); unsigned i, j; + int codesize = 0; FILE *dump = fopen("disasm.txt", "w"); for (i = 0; i < StateTempCalls.Size(); ++i) @@ -316,6 +317,7 @@ static void FinishThingdef() VMDumpConstants(dump, sfunc); fprintf(dump, "\nDisassembly @ %p:\n", sfunc->Code); VMDisasm(dump, sfunc->Code, sfunc->CodeSize, sfunc); + codesize += sfunc->CodeSize; #endif } for (int k = 0; k < tcall->NumStates; ++k) @@ -323,6 +325,9 @@ static void FinishThingdef() tcall->ActorClass->OwnedStates[tcall->FirstState + k].SetAction(func); } } +#if 1 + fprintf(dump, "\n*************************************************************************\n%i code bytes\n", codesize * 4); +#endif fclose(dump); for (i = 0; i < PClassActor::AllActorClasses.Size(); i++) diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 114c8a0b1..f60e69c40 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -613,7 +613,7 @@ void InitThingdef() { AFuncDesc *afunc = (AFuncDesc *)*probe; assert(afunc->VMPointer != NULL); - *(afunc->VMPointer) = new VMNativeFunction(afunc->Function); + *(afunc->VMPointer) = new VMNativeFunction(afunc->Function, afunc->Name); AFTable.Push(*afunc); } AFTable.ShrinkToFit(); diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 9f17e5678..7699750a2 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -2487,11 +2487,11 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build) // Find the DecoRandom function. If not found, create it and install it // in Actor. VMFunction *callfunc; - PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol("DecoRandom", false); + PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol(NAME_DecoRandom, false); if (sym == NULL) { - PSymbolVMFunction *symfunc = new PSymbolVMFunction("DecoRandom"); - VMNativeFunction *calldec = new VMNativeFunction(DecoRandom); + PSymbolVMFunction *symfunc = new PSymbolVMFunction(NAME_DecoRandom); + VMNativeFunction *calldec = new VMNativeFunction(DecoRandom, NAME_DecoRandom); symfunc->Function = calldec; sym = symfunc; RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); @@ -2593,11 +2593,11 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) // Find the DecoFRandom function. If not found, create it and install it // in Actor. VMFunction *callfunc; - PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol("DecoFRandom", false); + PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol(NAME_DecoFRandom, false); if (sym == NULL) { - PSymbolVMFunction *symfunc = new PSymbolVMFunction("DecoFRandom"); - VMNativeFunction *calldec = new VMNativeFunction(DecoFRandom); + PSymbolVMFunction *symfunc = new PSymbolVMFunction(NAME_DecoFRandom); + VMNativeFunction *calldec = new VMNativeFunction(DecoFRandom, NAME_DecoFRandom); symfunc->Function = calldec; sym = symfunc; RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); @@ -2683,11 +2683,11 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) // Find the DecoRandom function. If not found, create it and install it // in Actor. VMFunction *callfunc; - PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol("DecoRandom", false); + PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol(NAME_DecoRandom, false); if (sym == NULL) { - PSymbolVMFunction *symfunc = new PSymbolVMFunction("DecoRandom"); - VMNativeFunction *calldec = new VMNativeFunction(DecoRandom); + PSymbolVMFunction *symfunc = new PSymbolVMFunction(NAME_DecoRandom); + VMNativeFunction *calldec = new VMNativeFunction(DecoRandom, NAME_DecoRandom); symfunc->Function = calldec; sym = symfunc; RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); @@ -3530,11 +3530,11 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) // Find the DecoCallLineSpecial function. If not found, create it and install it // in Actor. VMFunction *callfunc; - PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol("DecoCallLineSpecial", false); + PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol(NAME_DecoCallLineSpecial, false); if (sym == NULL) { - PSymbolVMFunction *symfunc = new PSymbolVMFunction("DecoCallLineSpecial"); - VMNativeFunction *calldec = new VMNativeFunction(DecoCallLineSpecial); + PSymbolVMFunction *symfunc = new PSymbolVMFunction(NAME_DecoCallLineSpecial); + VMNativeFunction *calldec = new VMNativeFunction(DecoCallLineSpecial, NAME_DecoCallLineSpecial); symfunc->Function = calldec; sym = symfunc; RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); @@ -3795,11 +3795,11 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build) // Find the DecoNameToClass function. If not found, create it and install it // in Actor. VMFunction *callfunc; - PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol("DecoNameToClass", false); + PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol(NAME_DecoNameToClass, false); if (sym == NULL) { - PSymbolVMFunction *symfunc = new PSymbolVMFunction("DecoNameToClass"); - VMNativeFunction *calldec = new VMNativeFunction(DecoNameToClass); + PSymbolVMFunction *symfunc = new PSymbolVMFunction(NAME_DecoNameToClass); + VMNativeFunction *calldec = new VMNativeFunction(DecoNameToClass, NAME_DecoNameToClass); symfunc->Function = calldec; sym = symfunc; RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); @@ -3995,11 +3995,11 @@ ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build) // Find the DecoFindMultiNameState function. If not found, create it and install it // in Actor. VMFunction *callfunc; - PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol("DecoFindMultiNameState", false); + PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol(NAME_DecoNameToClass, false); if (sym == NULL) { - PSymbolVMFunction *symfunc = new PSymbolVMFunction("DecoFindMultiNameState"); - VMNativeFunction *calldec = new VMNativeFunction(DecoFindMultiNameState); + PSymbolVMFunction *symfunc = new PSymbolVMFunction(NAME_DecoNameToClass); + VMNativeFunction *calldec = new VMNativeFunction(DecoFindMultiNameState, NAME_DecoNameToClass); symfunc->Function = calldec; sym = symfunc; RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); diff --git a/src/zscript/vm.h b/src/zscript/vm.h index 41284f912..256578a8e 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -149,6 +149,10 @@ class VMFunction : public DObject DECLARE_ABSTRACT_CLASS(VMFunction, DObject); public: bool Native; + FName Name; + + VMFunction() : Native(false), Name(NAME_None) {} + VMFunction(FName name) : Native(false), Name(name) {} }; enum EVMOpMode @@ -712,7 +716,7 @@ struct VMRegisters struct VMException : public DObject { - DECLARE_CLASS(VMFunction, DObject); + DECLARE_CLASS(VMException, DObject); }; union FVoidObj @@ -725,7 +729,7 @@ class VMScriptFunction : public VMFunction { DECLARE_CLASS(VMScriptFunction, VMFunction); public: - VMScriptFunction(); + VMScriptFunction(FName name=NAME_None); ~VMScriptFunction(); size_t PropagateMark(); void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta); @@ -788,6 +792,7 @@ public: VMNativeFunction() : NativeCall(NULL) { Native = true; } VMNativeFunction(NativeCallType call) : NativeCall(call) { Native = true; } + VMNativeFunction(NativeCallType call, FName name) : VMFunction(name), NativeCall(call) { Native = true; } // Return value is the number of results. NativeCallType NativeCall; diff --git a/src/zscript/vmdisasm.cpp b/src/zscript/vmdisasm.cpp index 5e7d4e0cc..e81b4087b 100644 --- a/src/zscript/vmdisasm.cpp +++ b/src/zscript/vmdisasm.cpp @@ -173,6 +173,8 @@ void VMDumpConstants(FILE *out, const VMScriptFunction *func) void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction *func) { + VMFunction *callfunc; + const char *callname; const char *name; int col; int mode; @@ -212,6 +214,12 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction col = printf_wrapper(out, "%d", code[i].i24); break; + case OP_CALL_K: + callfunc = (VMFunction *)func->KonstA[code[i].a].o; + callname = callfunc->Name != NAME_None ? callfunc->Name : "[anonfunc]"; + col = printf_wrapper(out, "%.23s,%d,%d", callname, code[i].b, code[i].c); + break; + case OP_RET: if (code[i].b != REGT_NIL) { @@ -308,6 +316,10 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction { printf_wrapper(out, "%d\n", code[i].i24); } + else if (code[i].op == OP_CALL_K) + { + printf_wrapper(out, "%d,%d,%d [%p]\n", code[i].a, code[i].b, code[i].c, callfunc); + } else { printf_wrapper(out, "%d,%d,%d\n", code[i].a, code[i].b, code[i].c); diff --git a/src/zscript/vmframe.cpp b/src/zscript/vmframe.cpp index fdf2d42cc..0c2cacfc2 100644 --- a/src/zscript/vmframe.cpp +++ b/src/zscript/vmframe.cpp @@ -6,9 +6,10 @@ IMPLEMENT_ABSTRACT_CLASS(VMFunction) IMPLEMENT_CLASS(VMScriptFunction) IMPLEMENT_CLASS(VMNativeFunction) -VMScriptFunction::VMScriptFunction() +VMScriptFunction::VMScriptFunction(FName name) { Native = false; + Name = name; Code = NULL; KonstD = NULL; KonstF = NULL; From e1a2f3b546dd063a0edfef9eb69e90d872c4c816 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 17 Jul 2012 04:06:28 +0000 Subject: [PATCH 049/232] - Added the TAIL instruction to perform a CALL and a RET in the same instruction. The called function will pass its results directly to this function's caller. Eventually, this should be changed to do a proper tail call for scripted functions. SVN r3769 (scripting) --- src/thingdef/thingdef.cpp | 3 +-- src/zscript/vmbuilder.cpp | 2 +- src/zscript/vmdisasm.cpp | 23 +++++++++++++++++------ src/zscript/vmexec.h | 37 +++++++++++++++++++++++++++++++++++++ src/zscript/vmops.h | 2 ++ 5 files changed, 58 insertions(+), 9 deletions(-) diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 3b68851c8..4fa035633 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -300,8 +300,7 @@ static void FinishThingdef() p->Emit(&buildit); delete p; } - buildit.Emit(OP_CALL_K, buildit.GetConstantAddress(tcall->Function, ATAG_OBJECT), NAP + j, 0); - buildit.Emit(OP_RET, 0, REGT_NIL, 0); + buildit.Emit(OP_TAIL_K, buildit.GetConstantAddress(tcall->Function, ATAG_OBJECT), NAP + j, 0); VMScriptFunction *sfunc = buildit.MakeFunction(); sfunc->NumArgs = NAP; func = sfunc; diff --git a/src/zscript/vmbuilder.cpp b/src/zscript/vmbuilder.cpp index 60fe7817c..85e8c0469 100644 --- a/src/zscript/vmbuilder.cpp +++ b/src/zscript/vmbuilder.cpp @@ -430,7 +430,7 @@ size_t VMFunctionBuilder::Emit(int opcode, int opa, int opb, int opc) { ParamChange(1); } - else if (opcode == OP_CALL || opcode == OP_CALL_K) + else if (opcode == OP_CALL || opcode == OP_CALL_K || opcode == OP_TAIL || opcode == OP_TAIL_K) { ParamChange(-opb); } diff --git a/src/zscript/vmdisasm.cpp b/src/zscript/vmdisasm.cpp index e81b4087b..b68d3eb87 100644 --- a/src/zscript/vmdisasm.cpp +++ b/src/zscript/vmdisasm.cpp @@ -44,6 +44,8 @@ #define I24 MODE_ABCJOINT #define I8 MODE_AIMMZ | MODE_BUNUSED | MODE_CUNUSED #define __BCP MODE_AUNUSED | MODE_BCJOINT | MODE_BCPARAM +#define RPI8 MODE_AP | MODE_BIMMZ | MODE_CUNUSED +#define KPI8 MODE_AKP | MODE_BIMMZ | MODE_CUNUSED #define RPI8I8 MODE_AP | MODE_BIMMZ | MODE_CIMMZ #define KPI8I8 MODE_AKP | MODE_BIMMZ | MODE_CIMMZ #define I8BCP MODE_AIMMZ | MODE_BCJOINT | MODE_BCPARAM @@ -215,9 +217,14 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction break; case OP_CALL_K: + case OP_TAIL_K: callfunc = (VMFunction *)func->KonstA[code[i].a].o; callname = callfunc->Name != NAME_None ? callfunc->Name : "[anonfunc]"; - col = printf_wrapper(out, "%.23s,%d,%d", callname, code[i].b, code[i].c); + col = printf_wrapper(out, "%.23s,%d", callname, code[i].b); + if (code[i].op == OP_CALL_K) + { + printf_wrapper(out, ",%d", code[i].c); + } break; case OP_RET: @@ -316,13 +323,17 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction { printf_wrapper(out, "%d\n", code[i].i24); } - else if (code[i].op == OP_CALL_K) - { - printf_wrapper(out, "%d,%d,%d [%p]\n", code[i].a, code[i].b, code[i].c, callfunc); - } else { - printf_wrapper(out, "%d,%d,%d\n", code[i].a, code[i].b, code[i].c); + printf_wrapper(out, "%d,%d,%d", code[i].a, code[i].b, code[i].c); + if (code[i].op == OP_CALL_K || code[i].op == OP_TAIL_K) + { + printf_wrapper(out, " [%p]\n", callfunc); + } + else + { + printf_wrapper(out, "\n"); + } } } } diff --git a/src/zscript/vmexec.h b/src/zscript/vmexec.h index e9847946f..b59b44e94 100644 --- a/src/zscript/vmexec.h +++ b/src/zscript/vmexec.h @@ -539,6 +539,43 @@ begin: pc += C; // Skip RESULTs } NEXTOP; + OP(TAIL_K): + ASSERTKA(a); + assert(konstatag[a] == ATAG_OBJECT); + ptr = konsta[a].o; + goto Do_TAILCALL; + OP(TAIL): + ASSERTA(a); + ptr = reg.a[a]; + Do_TAILCALL: + assert(B <= f->NumParam); + assert(C <= MAX_RETURNS); + { + VMFunction *call = (VMFunction *)ptr; + + if (call->Native) + { + return static_cast<VMNativeFunction *>(call)->NativeCall(stack, reg.param + f->NumParam - B, B, ret, numret); + } + else + { // FIXME: Not a true tail call + VMScriptFunction *script = static_cast<VMScriptFunction *>(call); + VMFrame *newf = stack->AllocFrame(script); + VMFillParams(reg.param + f->NumParam - B, newf, B); + try + { + numret = Exec(stack, script->Code, ret, numret); + } + catch(...) + { + stack->PopFrame(); + throw; + } + stack->PopFrame(); + return numret; + } + } + NEXTOP; OP(RET): if (B == REGT_NIL) { // No return values diff --git a/src/zscript/vmops.h b/src/zscript/vmops.h index 20178dfb0..78ef5116f 100644 --- a/src/zscript/vmops.h +++ b/src/zscript/vmops.h @@ -77,6 +77,8 @@ xx(PARAM, param, __BCP), // push parameter encoded in BC for function call (B=r xx(PARAMI, parami, I24), // push immediate, signed integer for function call xx(CALL, call, RPI8I8), // Call function pkA with parameter count B and expected result count C xx(CALL_K, call, KPI8I8), +xx(TAIL, tail, RPI8), // Call+Ret in a single instruction +xx(TAIL_K, tail, KPI8), xx(RESULT, result, __BCP), // Result should go in register encoded in BC (in caller, after CALL) xx(RET, ret, I8BCP), // Copy value from register encoded in BC to return value A, possibly returning xx(TRY, try, I24), // When an exception is thrown, start searching for a handler at pc + ABC From fcceeb814a3d7b4e09930a8d2c731b9975e27f46 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 17 Jul 2012 05:31:41 +0000 Subject: [PATCH 050/232] - Changed state calls to use the VM's standard return value mechanism. StateCallData has been removed as a result, so now action functions take a minimum of three parameters rather than four. SVN r3770 (scripting) --- src/actor.h | 2 +- src/info.cpp | 5 +- src/info.h | 8 +- src/thingdef/thingdef.cpp | 5 +- src/thingdef/thingdef.h | 16 +- src/thingdef/thingdef_codeptr.cpp | 288 ++++++++++++++++-------------- src/zscript/vmdisasm.cpp | 4 +- 7 files changed, 165 insertions(+), 163 deletions(-) diff --git a/src/actor.h b/src/actor.h index f5cf9e648..b36f3667b 100644 --- a/src/actor.h +++ b/src/actor.h @@ -268,7 +268,7 @@ enum // --- mobj.flags5 --- - /* = 0x00000001, */ + MF5_INSTATECALL = 0x00000001, // This actor is being run through CallStateChain /* = 0x00000002, */ MF5_NODROPOFF = 0x00000004, // cannot drop off under any circumstances. /* = 0x00000008, */ diff --git a/src/info.cpp b/src/info.cpp index 76e2c11c4..01a3e3a25 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -57,13 +57,12 @@ extern void ClearStrifeTypes(); TArray<PClassActor *> PClassActor::AllActorClasses; -bool FState::CallAction(AActor *self, AActor *stateowner, StateCallData *statecall) +bool FState::CallAction(AActor *self, AActor *stateowner) { if (ActionFunc != NULL) { - //ActionFunc(self, stateowner, this, ParameterIndex-1, statecall); VMFrameStack stack; - VMValue params[4] = { self, stateowner, VMValue(this, ATAG_STATE), statecall }; + VMValue params[3] = { self, stateowner, VMValue(this, ATAG_STATE) }; stack.Call(ActionFunc, params, countof(params), NULL, 0, NULL); return true; } diff --git a/src/info.h b/src/info.h index 62f5f68dd..6a82f2a04 100644 --- a/src/info.h +++ b/src/info.h @@ -109,7 +109,7 @@ struct FState Frame = frame - 'A'; } void SetAction(VMFunction *func) { ActionFunc = func; } - bool CallAction(AActor *self, AActor *stateowner, StateCallData *statecall = NULL); + bool CallAction(AActor *self, AActor *stateowner); static PClassActor *StaticFindStateOwner (const FState *state); static PClassActor *StaticFindStateOwner (const FState *state, PClassActor *info); }; @@ -294,19 +294,17 @@ void AddStateLight(FState *state, const char *lname); // Standard parameters for all action functons // self - Actor this action is to operate on (player if a weapon) -// stateowner - Actor this action really belongs to (may be a weapon) +// stateowner - Actor this action really belongs to (may be an item) // callingstate - State this action was called from -// statecall - CustomInventory stuff #define PARAM_ACTION_PROLOGUE_TYPE(type) \ PARAM_PROLOGUE; \ PARAM_OBJECT (self, type); \ PARAM_OBJECT_OPT (stateowner, AActor) { stateowner = self; } \ PARAM_STATE_OPT (callingstate) { callingstate = NULL; } \ - PARAM_POINTER_OPT(statecall, StateCallData) { statecall = NULL; } #define PARAM_ACTION_PROLOGUE PARAM_ACTION_PROLOGUE_TYPE(AActor) // Number of action paramaters -#define NAP 4 +#define NAP 3 #endif // __INFO_H__ diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 4fa035633..b68c73c62 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -286,13 +286,12 @@ static void FinishThingdef() } VMFunctionBuilder buildit; // Allocate registers used to pass parameters in. - // self, stateowner, state, statecalldata (all are pointers) - buildit.Registers[REGT_POINTER].Get(4); + // self, stateowner, state (all are pointers) + buildit.Registers[REGT_POINTER].Get(3); // Emit code to pass the standard action function parameters. buildit.Emit(OP_PARAM, 0, REGT_POINTER, 0); buildit.Emit(OP_PARAM, 0, REGT_POINTER, 1); buildit.Emit(OP_PARAM, 0, REGT_POINTER, 2); - buildit.Emit(OP_PARAM, 0, REGT_POINTER, 3); // Emit code for action parameters. for (j = 0; j < tcall->Parameters.Size(); ++j) { diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index 29fd98e81..278ac6f8a 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -350,14 +350,6 @@ int MatchString (const char *in, const char **strings); MSVC_MSEG FVariableInfo *infoptr_GlobalDef__##name GCC_MSEG = &GlobalDef__##name; - - -struct StateCallData -{ - FState *State; - bool Result; -}; - // Macros to handle action functions. These are here so that I don't have to // change every single use in case the parameters change. #define DECLARE_ACTION(name) extern VMNativeFunction *name##_VMPtr; @@ -378,7 +370,7 @@ struct StateCallData //#define PUSH_PARAMINFO self, stateowner, CallingState, ParameterIndex, statecall #define CALL_ACTION(name,self) { /*AF_##name(self, self, NULL, 0, NULL)*/ \ - VMValue params[5] = { self, self, VMValue(NULL, ATAG_STATE), VMValue(NULL, ATAG_GENERIC) }; \ + VMValue params[3] = { self, self, VMValue(NULL, ATAG_STATE) }; \ stack->Call(name##_VMPtr, params, countof(params), NULL, 0, NULL); \ } @@ -421,10 +413,10 @@ FName EvalExpressionName (DWORD x, AActor *self); angle_t var = angle_t(EvalExpressionF(ParameterIndex+i, self)*ANGLE_90/90.f); #endif -#define ACTION_SET_RESULT(v) if (statecall != NULL) statecall->Result = v; +#define ACTION_SET_RESULT(v) do { if (numret > 0) { assert(ret != NULL); ret->SetInt(v); numret = 1; } } while(0) // Checks to see what called the current action function #define ACTION_CALL_FROM_ACTOR() (callingstate == self->state) -#define ACTION_CALL_FROM_WEAPON() (self->player && callingstate != self->state && statecall == NULL) -#define ACTION_CALL_FROM_INVENTORY() (statecall != NULL) +#define ACTION_CALL_FROM_WEAPON() (self->player && callingstate != self->state && !(stateowner->flags5 & MF5_INSTATECALL)) +#define ACTION_CALL_FROM_INVENTORY() (!(stateowner->flags5 & MF5_INSTATECALL)) #endif diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 89847f7c0..a9840d867 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -94,46 +94,59 @@ static FRandom pr_teleport("A_Teleport"); // //========================================================================== -bool ACustomInventory::CallStateChain (AActor *actor, FState * State) +bool ACustomInventory::CallStateChain (AActor *actor, FState *state) { - StateCallData StateCall; - bool result = false; + INTBOOL result = false; int counter = 0; + int retval, numret; + VMReturn ret; + ret.IntAt(&retval); + VMValue params[3] = { actor, this, 0 }; - while (State != NULL) + this->flags5 |= MF5_INSTATECALL; + FState *savedstate = this->state; + + while (state != NULL) { - // Assume success. The code pointer will set this to false if necessary - StateCall.State = State; - StateCall.Result = true; - if (State->CallAction(actor, this, &StateCall)) - { - // collect all the results. Even one successful call signifies overall success. - result |= StateCall.Result; - } + this->state = state; + if (state->ActionFunc != NULL) + { + VMFrameStack stack; + + params[2] = VMValue(state, ATAG_STATE); + retval = true; // assume success + numret = stack.Call(state->ActionFunc, params, countof(params), &ret, 1); + // As long as even one state succeeds, the whole chain succeeds unless aborted below. + result |= retval; + } // Since there are no delays it is a good idea to check for infinite loops here! counter++; if (counter >= 10000) break; - if (StateCall.State == State) + if (this->state == state) { - // Abort immediately if the state jumps to itself! - if (State == State->GetNextState()) - { - return false; + FState *next = state->GetNextState(); + + if (state == next) + { // Abort immediately if the state jumps to itself! + result = false; + break; } // If both variables are still the same there was no jump // so we must advance to the next state. - State = State->GetNextState(); + state = next; } else { - State = StateCall.State; + state = this->state; } } - return result; + this->flags5 &= ~MF5_INSTATECALL; + this->state = savedstate; + return !!result; } //========================================================================== @@ -579,13 +592,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_BulletAttack) // Do the state jump // //========================================================================== -static void DoJump(AActor *self, FState *callingstate, FState *jumpto, StateCallData *statecall) +static void DoJump(AActor *self, AActor *stateowner, FState *callingstate, FState *jumpto) { if (jumpto == NULL) return; - if (statecall != NULL) + if (stateowner->flags5 & MF5_INSTATECALL) { - statecall->State = jumpto; + stateowner->state = jumpto; } else if (self->player != NULL && callingstate == self->player->psprites[ps_weapon].state) { @@ -600,15 +613,14 @@ static void DoJump(AActor *self, FState *callingstate, FState *jumpto, StateCall self->SetState(jumpto); } else - { - // something went very wrong. This should never happen. + { // something went very wrong. This should never happen. assert(false); } } // This is just to avoid having to directly reference the internally defined // CallingState and statecall parameters in the code below. -#define ACTION_JUMP(offset) DoJump(self, callingstate, offset, statecall) +#define ACTION_JUMP(offset) DoJump(self, stateowner, callingstate, offset) //========================================================================== // @@ -629,7 +641,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Jump) ACTION_JUMP(jumpto); } ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - return 0; + return numret; } //========================================================================== @@ -648,7 +660,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfHealthLower) ACTION_JUMP(jump); } ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - return 0; + return numret; } //========================================================================== @@ -656,7 +668,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfHealthLower) // State jump function // //========================================================================== -void DoJumpIfCloser(AActor *target, VM_ARGS) +static int DoJumpIfCloser(AActor *target, VM_ARGS) { PARAM_ACTION_PROLOGUE; PARAM_FIXED (dist); @@ -673,6 +685,7 @@ void DoJumpIfCloser(AActor *target, VM_ARGS) { ACTION_JUMP(jump); } + return numret; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfCloser) @@ -690,22 +703,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfCloser) // Does the player aim at something that can be shot? P_BulletSlope(self, &target); } - DoJumpIfCloser(target, VM_ARGS_NAMES); - return 0; + return DoJumpIfCloser(target, VM_ARGS_NAMES); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTracerCloser) { PARAM_ACTION_PROLOGUE; - DoJumpIfCloser(self->tracer, VM_ARGS_NAMES); - return 0; + return DoJumpIfCloser(self->tracer, VM_ARGS_NAMES); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfMasterCloser) { PARAM_ACTION_PROLOGUE; - DoJumpIfCloser(self->master, VM_ARGS_NAMES); - return 0; + return DoJumpIfCloser(self->master, VM_ARGS_NAMES); } //========================================================================== @@ -713,7 +723,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfMasterCloser) // State jump function // //========================================================================== -int DoJumpIfInventory(AActor *owner, AActor *self, StateCallData *statecall, FState *callingstate, VMValue *param, int numparam) +int DoJumpIfInventory(AActor *owner, AActor *self, AActor *stateowner, FState *callingstate, VMValue *param, int numparam, VMReturn *ret, int numret) { int paramnum = NAP-1; PARAM_CLASS (itemtype, AInventory); @@ -725,12 +735,12 @@ int DoJumpIfInventory(AActor *owner, AActor *self, StateCallData *statecall, FSt if (itemtype == NULL) { - return 0; + return numret; } owner = COPY_AAPTR(owner, setowner); if (owner == NULL) { - return 0; + return numret; } AInventory *item = owner->FindInventory(itemtype); @@ -747,19 +757,19 @@ int DoJumpIfInventory(AActor *owner, AActor *self, StateCallData *statecall, FSt ACTION_JUMP(label); } } - return 0; + return numret; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInventory) { PARAM_ACTION_PROLOGUE; - return DoJumpIfInventory(self, self, statecall, callingstate, param, numparam); + return DoJumpIfInventory(self, self, stateowner, callingstate, param, numparam, ret, numret); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetInventory) { PARAM_ACTION_PROLOGUE; - return DoJumpIfInventory(self->target, self, statecall, callingstate, param, numparam); + return DoJumpIfInventory(self->target, self, stateowner, callingstate, param, numparam, ret, numret); } //========================================================================== @@ -780,7 +790,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfArmorType) if (armor && armor->ArmorType == type && armor->Amount >= amount) ACTION_JUMP(label); - return 0; + return numret; } //========================================================================== @@ -906,7 +916,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CallSpecial) bool res = !!P_ExecuteSpecial(special, NULL, self, false, arg1, arg2, arg3, arg4, arg5); ACTION_SET_RESULT(res); - return 0; + return numret; } //========================================================================== @@ -1229,13 +1239,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfNoAmmo) ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! if (!ACTION_CALL_FROM_WEAPON()) - return 0; + return numret; if (!self->player->ReadyWeapon->CheckAmmo(self->player->ReadyWeapon->bAltFire, false, true)) { ACTION_JUMP(jump); } - return 0; + return numret; } @@ -1659,7 +1669,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) // //=========================================================================== -static int DoGiveInventory(AActor *receiver, StateCallData *statecall, VM_ARGS) +static int DoGiveInventory(AActor *receiver, VM_ARGS) { int paramnum = NAP-1; PARAM_CLASS (mi, AInventory); @@ -1668,8 +1678,9 @@ static int DoGiveInventory(AActor *receiver, StateCallData *statecall, VM_ARGS) receiver = COPY_AAPTR(receiver, setreceiver); if (receiver == NULL) - { - return 0; + { // If there's nothing to receive it, it's obviously a fail, right? + ACTION_SET_RESULT(false); + return numret; } bool res = true; @@ -1706,19 +1717,19 @@ static int DoGiveInventory(AActor *receiver, StateCallData *statecall, VM_ARGS) res = false; } ACTION_SET_RESULT(res); - return 0; + return numret; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveInventory) { PARAM_ACTION_PROLOGUE; - return DoGiveInventory(self, statecall, VM_ARGS_NAMES); + return DoGiveInventory(self, VM_ARGS_NAMES); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToTarget) { PARAM_ACTION_PROLOGUE; - return DoGiveInventory(self->target, statecall, VM_ARGS_NAMES); + return DoGiveInventory(self->target, VM_ARGS_NAMES); } //=========================================================================== @@ -1732,7 +1743,7 @@ enum TIF_NOTAKEINFINITE = 1, }; -int DoTakeInventory(AActor *receiver, StateCallData *statecall, VM_ARGS) +int DoTakeInventory(AActor *receiver, VM_ARGS) { int paramnum = NAP-1; PARAM_CLASS (itemtype, AInventory); @@ -1742,12 +1753,14 @@ int DoTakeInventory(AActor *receiver, StateCallData *statecall, VM_ARGS) if (itemtype == NULL) { - return 0; + ACTION_SET_RESULT(true); + return numret; } receiver = COPY_AAPTR(receiver, setreceiver); if (receiver == NULL) { - return 0; + ACTION_SET_RESULT(false); + return numret; } bool res = false; @@ -1779,19 +1792,19 @@ int DoTakeInventory(AActor *receiver, StateCallData *statecall, VM_ARGS) } } ACTION_SET_RESULT(res); - return 0; + return numret; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeInventory) { PARAM_ACTION_PROLOGUE; - return DoTakeInventory(self, statecall, VM_ARGS_NAMES); + return DoTakeInventory(self, VM_ARGS_NAMES); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeFromTarget) { PARAM_ACTION_PROLOGUE; - return DoTakeInventory(self->target, statecall, VM_ARGS_NAMES); + return DoTakeInventory(self->target, VM_ARGS_NAMES); } //=========================================================================== @@ -1908,12 +1921,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItem) if (missile == NULL) { ACTION_SET_RESULT(false); - return 0; + return numret; } + ACTION_SET_RESULT(true); // Don't spawn monsters if this actor has been massacred if (self->DamageType == NAME_Massacre && (GetDefaultByType(missile)->flags3 & MF3_ISMONSTER)) - return 0; + { + return numret; + } if (distance == 0) { @@ -1927,9 +1943,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItem) AWeapon *weapon = self->player->ReadyWeapon; if (weapon == NULL) - return 0; + return numret; if (useammo && !weapon->DepleteAmmo(weapon->bAltFire)) - return 0; + return numret; } AActor *mo = Spawn(missile, @@ -1940,7 +1956,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItem) int flags = (transfer_translation ? SIXF_TRANSFERTRANSLATION : 0) + (useammo ? SIXF_SETMASTER : 0); bool res = InitSpawnedItem(self, mo, flags); ACTION_SET_RESULT(res); // for an inventory item's use state - return 0; + return numret; } //=========================================================================== @@ -1967,15 +1983,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) if (missile == NULL) { ACTION_SET_RESULT(false); - return 0; + return numret; } + ACTION_SET_RESULT(true); if (chance > 0 && pr_spawnitemex() < chance) - return 0; + return numret; // Don't spawn monsters if this actor has been massacred if (self->DamageType == NAME_Massacre && (GetDefaultByType(missile)->flags3 & MF3_ISMONSTER)) - return 0; + return numret; fixed_t x, y; @@ -2019,7 +2036,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) if (flags & SIXF_TRANSFERAMBUSHFLAG) mo->flags = (mo->flags & ~MF_AMBUSH) | (self->flags & MF_AMBUSH); } - return 0; + return numret; } //=========================================================================== @@ -2038,8 +2055,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ThrowGrenade) PARAM_FIXED_OPT (zvel) { zvel = 0; } PARAM_BOOL_OPT (useammo) { useammo = true; } + ACTION_SET_RESULT(true); if (missile == NULL) - return 0; + return numret; if (ACTION_CALL_FROM_WEAPON()) { @@ -2047,9 +2065,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ThrowGrenade) AWeapon *weapon = self->player->ReadyWeapon; if (weapon == NULL) - return 0; + return numret; if (useammo && !weapon->DepleteAmmo(weapon->bAltFire)) - return 0; + return numret; } AActor *bo; @@ -2093,7 +2111,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ThrowGrenade) { ACTION_SET_RESULT(false); } - return 0; + return numret; } @@ -2128,7 +2146,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SelectWeapon) if (cls == NULL || self->player == NULL) { ACTION_SET_RESULT(false); - return 0; + return numret; } AWeapon *weaponitem = static_cast<AWeapon*>(self->FindInventory(cls)); @@ -2139,12 +2157,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SelectWeapon) { self->player->PendingWeapon = weaponitem; } + ACTION_SET_RESULT(true); } else { ACTION_SET_RESULT(false); } - return 0; + return numret; } @@ -2181,7 +2200,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Print) con_midtime = saved; } ACTION_SET_RESULT(false); // Prints should never set the result for inventory state chains! - return 0; + return numret; } //=========================================================================== @@ -2212,7 +2231,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PrintBold) C_MidPrintBold(font != NULL ? font : SmallFont, formatted.GetChars()); con_midtime = saved; ACTION_SET_RESULT(false); // Prints should never set the result for inventory state chains! - return 0; + return numret; } //=========================================================================== @@ -2227,7 +2246,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Log) PARAM_STRING(text); Printf("%s\n", text); ACTION_SET_RESULT(false); // Prints should never set the result for inventory state chains! - return 0; + return numret; } //=========================================================================== @@ -2242,7 +2261,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LogInt) PARAM_INT(num); Printf("%d\n", num); ACTION_SET_RESULT(false); // Prints should never set the result for inventory state chains! - return 0; + return numret; } //=========================================================================== @@ -2453,19 +2472,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSight) // Always check sight from each player. if (P_CheckSight(players[i].mo, self, SF_IGNOREVISIBILITY)) { - return 0; + return numret; } // If a player is viewing from a non-player, then check that too. if (players[i].camera != NULL && players[i].camera->player == NULL && P_CheckSight(players[i].camera, self, SF_IGNOREVISIBILITY)) { - return 0; + return numret; } } } ACTION_JUMP(jump); - return 0; + return numret; } //=========================================================================== @@ -2527,18 +2546,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSightOrRange) // Always check from each player. if (DoCheckSightOrRange(self, players[i].mo, range)) { - return 0; + return numret; } // If a player is viewing from a non-player, check that too. if (players[i].camera != NULL && players[i].camera->player == NULL && DoCheckSightOrRange(self, players[i].camera, range)) { - return 0; + return numret; } } } ACTION_JUMP(jump); - return 0; + return numret; } @@ -2605,7 +2624,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIf) ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! if (condition) ACTION_JUMP(jump); - return 0; + return numret; } //=========================================================================== @@ -2781,7 +2800,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckFloor) { ACTION_JUMP(jump); } - return 0; + return numret; } //=========================================================================== @@ -2801,7 +2820,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckCeiling) { ACTION_JUMP(jump); } - return 0; + return numret; } //=========================================================================== @@ -2945,7 +2964,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlayerSkinCheck) { ACTION_JUMP(jump); } - return 0; + return numret; } //=========================================================================== @@ -3045,11 +3064,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) } if (target == NULL) - return 0; // [KS] Let's not call P_CheckSight unnecessarily in this case. + return numret; // [KS] Let's not call P_CheckSight unnecessarily in this case. if ((flags & JLOSF_DEADNOJUMP) && (target->health <= 0)) { - return 0; + return numret; } doCheckSight = !(flags & JLOSF_NOSIGHT); @@ -3059,7 +3078,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) // Does the player aim at something that can be shot? P_BulletSlope(self, &target); - if (!target) return 0; + if (!target) return numret; switch (flags & (JLOSF_TARGETLOS|JLOSF_FLIPFOV)) { @@ -3082,22 +3101,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) // [FDARI] If target is not a combatant, don't jump if ( (flags & JLOSF_COMBATANTONLY) && (!target->player) && !(target->flags3 & MF3_ISMONSTER)) - return 0; + return numret; // [FDARI] If actors share team, don't jump if ((flags & JLOSF_ALLYNOJUMP) && self->IsFriend(target)) - return 0; + return numret; fixed_t distance = P_AproxDistance(target->x - self->x, target->y - self->y); distance = P_AproxDistance(distance, target->z - self->z); if (dist_max && (distance > dist_max)) - return 0; + return numret; if (dist_close && (distance < dist_close)) { if (flags & JLOSF_CLOSENOJUMP) - return 0; + return numret; if (flags & JLOSF_CLOSENOFOV) fov = 0; @@ -3110,7 +3129,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) else { viewport = self; } if (doCheckSight && !P_CheckSight (viewport, target, SF_IGNOREVISIBILITY)) - return 0; + return numret; if (flags & JLOSF_FLIPFOV) { @@ -3128,13 +3147,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2))) { - return 0; // [KS] Outside of FOV - return + return numret; // [KS] Outside of FOV - return } } ACTION_JUMP(jump); - return 0; + return numret; } @@ -3177,12 +3196,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) if (target == NULL) { // [KS] Let's not call P_CheckSight unnecessarily in this case. - return 0; + return numret; } if ((flags & JLOSF_DEADNOJUMP) && (target->health <= 0)) { - return 0; + return numret; } fixed_t distance = P_AproxDistance(target->x - self->x, target->y - self->y); @@ -3190,7 +3209,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) if (dist_max && (distance > dist_max)) { - return 0; + return numret; } bool doCheckSight = !(flags & JLOSF_NOSIGHT); @@ -3198,7 +3217,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) if (dist_close && (distance < dist_close)) { if (flags & JLOSF_CLOSENOJUMP) - return 0; + return numret; if (flags & JLOSF_CLOSENOFOV) fov = 0; @@ -3217,14 +3236,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2))) { - return 0; // [KS] Outside of FOV - return + return numret; // [KS] Outside of FOV - return } } if (doCheckSight && !P_CheckSight (target, self, SF_IGNOREVISIBILITY)) - return 0; + return numret; ACTION_JUMP(jump); - return 0; + return numret; } @@ -3510,7 +3529,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckFlag) AActor *owner = COPY_AAPTR(self, checkpointer); if (owner == NULL) { - return 0; + return numret; } long dot = flagname.IndexOf('.'); @@ -3545,7 +3564,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckFlag) { Printf("Unknown flag '%s' in '%s'\n", flagname, cls->TypeName.GetChars()); } - return 0; + return numret; } @@ -3686,7 +3705,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MonsterRefire) A_FaceTarget(self); if (pr_monsterrefire() < prob) - return 0; + return numret; if (self->target == NULL || P_HitFriend (self) @@ -3695,7 +3714,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MonsterRefire) { ACTION_JUMP(jump); } - return 0; + return numret; } //=========================================================================== @@ -3956,6 +3975,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) PARAM_FIXED_OPT (mindist) { mindist = 128 << FRACBITS; } PARAM_FIXED_OPT (maxdist) { maxdist = 128 << FRACBITS; } + ACTION_SET_RESULT(true); + // Randomly choose not to teleport like A_Srcr2Decide. if (flags & TF_RANDOMDECIDE) { @@ -3973,7 +3994,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) if (pr_teleport() >= chance[chanceindex]) { - return 0; + return numret; } } @@ -3984,14 +4005,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) // If still nothing, then return. if (teleport_state == NULL) { - return 0; + return numret; } } DSpotState *state = DSpotState::GetSpotState(); if (state == NULL) { - return 0; + return numret; } if (target_type == NULL) @@ -4002,7 +4023,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) AActor *spot = state->GetSpotWithMinMaxDistance(target_type, self->x, self->y, mindist, maxdist); if (spot == NULL) { - return 0; + return numret; } fixed_t prevX = self->x; @@ -4023,7 +4044,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) self->angle = spot->angle; self->velx = self->vely = self->velz = 0; } - return 0; + return numret; } //=========================================================================== @@ -4153,7 +4174,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LineEffect) } } ACTION_SET_RESULT(res); - return 0; + return numret; } //========================================================================== @@ -4320,7 +4341,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) if (!reference) { ACTION_SET_RESULT(false); - return 0; + return numret; } if (!(flags & WARPF_ABSOLUTEANGLE)) @@ -4424,7 +4445,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! // in this case, you have the statejump to help you handle all the success anyway. ACTION_JUMP(success_state); - return 0; + return numret; } ACTION_SET_RESULT(true); @@ -4434,7 +4455,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) self->SetOrigin(oldx, oldy, oldz); ACTION_SET_RESULT(false); } - return 0; + return numret; } //========================================================================== @@ -4458,10 +4479,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedExecuteWithResult) PARAM_INT_OPT (arg3) { arg3 = 0; } PARAM_INT_OPT (arg4) { arg4 = 0; } - bool res = !!P_ExecuteSpecial(ACS_ExecuteWithResult, NULL, self, false, -scriptname, arg1, arg2, arg3, arg4); - + int res = P_ExecuteSpecial(ACS_ExecuteWithResult, NULL, self, false, -scriptname, arg1, arg2, arg3, arg4); ACTION_SET_RESULT(res); - return 0; + return numret; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedExecute) @@ -4473,10 +4493,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedExecute) PARAM_INT_OPT (arg2) { arg2 = 0; } PARAM_INT_OPT (arg3) { arg3 = 0; } - bool res = !!P_ExecuteSpecial(ACS_Execute, NULL, self, false, -scriptname, mapnum, arg1, arg2, arg3); - + int res = P_ExecuteSpecial(ACS_Execute, NULL, self, false, -scriptname, mapnum, arg1, arg2, arg3); ACTION_SET_RESULT(res); - return 0; + return numret; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedExecuteAlways) @@ -4488,10 +4507,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedExecuteAlways) PARAM_INT_OPT (arg2) { arg2 = 0; } PARAM_INT_OPT (arg3) { arg3 = 0; } - bool res = !!P_ExecuteSpecial(ACS_ExecuteAlways, NULL, self, false, -scriptname, mapnum, arg1, arg2, arg3); - + int res = P_ExecuteSpecial(ACS_ExecuteAlways, NULL, self, false, -scriptname, mapnum, arg1, arg2, arg3); ACTION_SET_RESULT(res); - return 0; + return numret; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedLockedExecute) @@ -4503,10 +4521,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedLockedExecute) PARAM_INT_OPT (arg2) { arg2 = 0; } PARAM_INT_OPT (lock) { lock = 0; } - bool res = !!P_ExecuteSpecial(ACS_LockedExecute, NULL, self, false, -scriptname, mapnum, arg1, arg2, lock); - + int res = P_ExecuteSpecial(ACS_LockedExecute, NULL, self, false, -scriptname, mapnum, arg1, arg2, lock); ACTION_SET_RESULT(res); - return 0; + return numret; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedLockedExecuteDoor) @@ -4518,10 +4535,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedLockedExecuteDoor) PARAM_INT_OPT (arg2) { arg2 = 0; } PARAM_INT_OPT (lock) { lock = 0; } - bool res = !!P_ExecuteSpecial(ACS_LockedExecuteDoor, NULL, self, false, -scriptname, mapnum, arg1, arg2, lock); - + int res = P_ExecuteSpecial(ACS_LockedExecuteDoor, NULL, self, false, -scriptname, mapnum, arg1, arg2, lock); ACTION_SET_RESULT(res); - return 0; + return numret; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedSuspend) @@ -4530,10 +4546,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedSuspend) PARAM_NAME (scriptname); PARAM_INT_OPT (mapnum) { mapnum = 0; } - bool res = !!P_ExecuteSpecial(ACS_Suspend, NULL, self, false, -scriptname, mapnum, 0, 0, 0); - + int res = P_ExecuteSpecial(ACS_Suspend, NULL, self, false, -scriptname, mapnum, 0, 0, 0); ACTION_SET_RESULT(res); - return 0; + return numret; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedTerminate) @@ -4542,10 +4557,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedTerminate) PARAM_NAME (scriptname); PARAM_INT_OPT (mapnum) { mapnum = 0; } - bool res = !!P_ExecuteSpecial(ACS_Terminate, NULL, self, false, -scriptname, mapnum, 0, 0, 0); - + int res = P_ExecuteSpecial(ACS_Terminate, NULL, self, false, -scriptname, mapnum, 0, 0, 0); ACTION_SET_RESULT(res); - return 0; + return numret; } diff --git a/src/zscript/vmdisasm.cpp b/src/zscript/vmdisasm.cpp index b68d3eb87..04c3bbb9c 100644 --- a/src/zscript/vmdisasm.cpp +++ b/src/zscript/vmdisasm.cpp @@ -223,7 +223,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction col = printf_wrapper(out, "%.23s,%d", callname, code[i].b); if (code[i].op == OP_CALL_K) { - printf_wrapper(out, ",%d", code[i].c); + col += printf_wrapper(out, ",%d", code[i].c); } break; @@ -328,7 +328,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction printf_wrapper(out, "%d,%d,%d", code[i].a, code[i].b, code[i].c); if (code[i].op == OP_CALL_K || code[i].op == OP_TAIL_K) { - printf_wrapper(out, " [%p]\n", callfunc); + printf_wrapper(out, " [%p]\n", callfunc); } else { From a5c938445a7b22e2a227402b6a344dba8ae14c3f Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 20 Jul 2012 01:07:04 +0000 Subject: [PATCH 051/232] - Oh look! It's a comment that didn't get saved before the last commit! SVN r3772 (scripting) --- src/zscript/vmexec.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/zscript/vmexec.h b/src/zscript/vmexec.h index b59b44e94..71d71f065 100644 --- a/src/zscript/vmexec.h +++ b/src/zscript/vmexec.h @@ -548,6 +548,8 @@ begin: ASSERTA(a); ptr = reg.a[a]; Do_TAILCALL: + // Whereas the CALL instruction uses its third operand to specify how many return values + // it expects, TAIL ignores its third operand and uses whatever was passed to this Exec call. assert(B <= f->NumParam); assert(C <= MAX_RETURNS); { From 2d139f38466df90f91cf8c04e9c7a7fe6176fd70 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 20 Jul 2012 02:54:51 +0000 Subject: [PATCH 052/232] - DoParse() now writes out the parsed AST for the input file to <file>.ast. Maybe TODO: Find a simple LISP pretty printer that isn't written in LISP so that the output isn't all on one big long line. - zcc-parse.lemon now returns the complete AST through the parse state. - Fixed crash in PrintEnumNode(). SVN r3773 (scripting) --- src/zscript/ast.cpp | 2 +- src/zscript/zcc-parse.lemon | 20 +++++++++++--------- src/zscript/zcc_parser.cpp | 9 +++++++++ src/zscript/zcc_parser.h | 3 ++- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/zscript/ast.cpp b/src/zscript/ast.cpp index 5757e4b04..d4a98691e 100644 --- a/src/zscript/ast.cpp +++ b/src/zscript/ast.cpp @@ -141,7 +141,7 @@ static void PrintEnum(FString &out, ZCC_TreeNode *node) static void PrintEnumNode(FString &out, ZCC_TreeNode *node) { ZCC_EnumNode *enode = (ZCC_EnumNode *)node; - out.AppendFormat("(enum-node '%s' ", FName(enode->ElemName)); + out.AppendFormat("(enum-node '%s' ", FName(enode->ElemName).GetChars()); PrintNodes(out, enode->ElemValue, ')'); } diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index 8f029b83f..ba2776d4b 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -69,14 +69,16 @@ %type opt_func_body {ZCC_CompoundStmt *} %type function_body {ZCC_CompoundStmt *} -main ::= translation_unit. { stat->sc.ScriptMessage("Parse complete\n"); } +main ::= translation_unit(A). { stat->TopNode = A; stat->sc.ScriptMessage("Parse complete\n"); } -translation_unit ::= . -translation_unit ::= translation_unit external_declaration. -translation_unit ::= translation_unit EOF. -translation_unit ::= error. +%type translation_unit {ZCC_TreeNode *} +translation_unit(X) ::= . { X = NULL; } +translation_unit(X) ::= translation_unit(A) external_declaration(B). { SAFE_APPEND(A,B); X = A; } +translation_unit(X) ::= translation_unit(A) EOF. { X = A; } +translation_unit(X) ::= error. { X = NULL; } -external_declaration ::= class_definition. +%type external_declaration {ZCC_TreeNode *} +external_declaration(X) ::= class_definition(A). { X = A; } /* Optional bits. */ opt_semicolon ::= . @@ -317,7 +319,6 @@ state_line(X) ::= NWS(A) NWS(B) expr state_opts(C) state_action(D). { NEW_AST_NODE(StateLine, line); const char *sprite = FName(A.Name()).GetChars(); - memset(line, 0, sizeof(*line)); if (strlen(sprite) != 4) { Printf("Sprite name '%s' must be four characters", sprite); @@ -650,7 +651,7 @@ func_params(X) ::= VOID. { X = NULL; } func_params(X) ::= func_param_list(A). { X = A; } func_param_list(X) ::= func_param(A). { X = A; } -func_param_list(X) ::= func_param(A) COMMA func_param_list(B). { X = A; A->AppendSibling(B); } +func_param_list(X) ::= func_param_list(A) COMMA func_param(B). { X = A; A->AppendSibling(B); } func_param(X) ::= func_param_flags(A) type(B) IDENTIFIER(C). { @@ -1194,7 +1195,8 @@ iteration_statement(X) ::= FOR LPAREN for_init(IN) SEMICOLON opt_expr(EX) SEMICO iter->LoopBumper = DO; iter->CheckAt = ZCC_IterationStmt::Start; // The initialization expression appears outside the loop - IN->AppendSibling(iter); + // for_init may be NULL if there is no initialization. + SAFE_APPEND(IN, iter); // And the whole thing gets wrapped inside a compound statement in case the loop // initializer defined any variables. NEW_AST_NODE(CompoundStmt, wrap); diff --git a/src/zscript/zcc_parser.cpp b/src/zscript/zcc_parser.cpp index 69e501d10..32816ec0c 100644 --- a/src/zscript/zcc_parser.cpp +++ b/src/zscript/zcc_parser.cpp @@ -229,6 +229,15 @@ static void DoParse(const char *filename) fclose(f); } #endif + FString ast = ZCC_PrintAST(state.TopNode); + FString astfile = ExtractFileBase(filename, false); + astfile << ".ast"; + f = fopen(astfile, "w"); + if (f != NULL) + { + fputs(ast.GetChars(), f); + fclose(f); + } } CCMD(parse) diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index 5256e4637..d0d4e3b63 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -7,6 +7,7 @@ struct ZCCParseState FScanner ≻ FSharedStringArena Strings; FMemArena SyntaxArena; + struct ZCC_TreeNode *TopNode; }; union ZCCToken @@ -206,7 +207,7 @@ struct ZCC_TreeNode } // The new sibling node should only be in a list with itself. - assert(sibling->SiblingNext == sibling && sibling->SiblingNext == sibling); + assert(sibling->SiblingNext == sibling && sibling->SiblingPrev == sibling); // Check integrity of our sibling list. assert(SiblingPrev->SiblingNext == this); From 38d7b7d203999ad51d73bddf7cd41fe69a84d78e Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Thu, 18 Oct 2012 03:19:27 +0000 Subject: [PATCH 053/232] - Fixed errors and warnings when compiling with GCC. (Unfortunately, the VC++ debug builds become ungodly slow when using mods with complex DECORATE. The GCC debug builds run just fine, however. Hopefully this is something that can be fixed later with an assembly-optimized version of the main VM loop, because I don't relish the thought of being stuck with GDB for debugging.) - Fixed: The ACS_Named* action specials were erroneously defined as taking strings instead of names. - Fixed: Copy-paste error caused FxMultiNameState::Emit to generate code that called DecoNameToClass instead of DecoFindMultiNameState. - Updated FxActionSpecialCall::Emit for named script specials. - Fixed inverted asserts for FxMinusSign::Emit and FxUnaryNotBitwise::Emit. SVN r3893 (scripting) --- src/CMakeLists.txt | 7 +----- src/actor.h | 8 +++---- src/d_dehacked.cpp | 2 +- src/dobject.h | 1 + src/dobjtype.cpp | 12 +++++----- src/dthinker.h | 4 ++-- src/farchive.h | 2 +- src/g_shared/a_pickups.cpp | 2 +- src/g_shared/shared_sbar.cpp | 14 ++++++------ src/g_strife/a_thingstoblowup.cpp | 2 +- src/menu/menu.cpp | 2 +- src/p_mobj.cpp | 2 +- src/p_user.cpp | 4 ++-- src/r_data/sprites.cpp | 2 +- src/r_utility.cpp | 2 +- src/thingdef/thingdef_codeptr.cpp | 10 ++++----- src/thingdef/thingdef_expression.cpp | 33 ++++++++++++++++++---------- src/thingdef/thingdef_properties.cpp | 2 +- src/zscript/vmbuilder.cpp | 2 +- src/zscript/vmdisasm.cpp | 2 +- src/zscript/vmexec.h | 2 +- src/zscript/zcc_parser.cpp | 7 ++++-- wadsrc/static/actors/actor.txt | 14 ++++++------ 23 files changed, 73 insertions(+), 65 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4465b32d0..a96c5d097 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -566,11 +566,6 @@ else( NO_ASM ) ADD_ASM_FILE( asm_ia32 tmap2 ) ADD_ASM_FILE( asm_ia32 tmap3 ) endif( X64 ) - if( WIN32 ) - if( NOT X64 ) - ADD_ASM_FILE( win32 wrappers ) - endif( NOT X64 ) - endif( WIN32 ) endif( NO_ASM ) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.h @@ -880,7 +875,6 @@ add_executable( zdoom WIN32 thingdef/thingdef_data.cpp thingdef/thingdef_exp.cpp thingdef/thingdef_expression.cpp - thingdef/thingdef_function.cpp thingdef/thingdef_parse.cpp thingdef/thingdef_properties.cpp thingdef/thingdef_states.cpp @@ -910,6 +904,7 @@ add_executable( zdoom WIN32 r_data/renderstyle.cpp r_data/r_interpolate.cpp r_data/r_translate.cpp + zscript/ast.cpp zscript/vmbuilder.cpp zscript/vmdisasm.cpp zscript/vmexec.cpp diff --git a/src/actor.h b/src/actor.h index 4e0b0de06..995c4d073 100644 --- a/src/actor.h +++ b/src/actor.h @@ -500,7 +500,7 @@ inline AActor *GetDefaultByType (const PClass *type) template<class T> inline T *GetDefault () { - return (T *)(RUNTIME_CLASS(T)->Defaults); + return (T *)(RUNTIME_CLASS_CASTLESS(T)->Defaults); } struct line_t; @@ -634,7 +634,7 @@ public: AInventory *FindInventory (FName type); template<class T> T *FindInventory () { - return static_cast<T *> (FindInventory (RUNTIME_CLASS(T))); + return static_cast<T *> (FindInventory (RUNTIME_TEMPLATE_CLASS(T))); } // Adds one item of a particular type. Returns NULL if it could not be added. @@ -1018,7 +1018,7 @@ public: do { actor = FActorIterator::Next (); - } while (actor && !actor->IsKindOf (RUNTIME_CLASS(T))); + } while (actor && !actor->IsKindOf (RUNTIME_TEMPLATE_CLASS(T))); return static_cast<T *>(actor); } }; @@ -1055,7 +1055,7 @@ AActor *Spawn (FName classname, fixed_t x, fixed_t y, fixed_t z, replace_t allow template<class T> inline T *Spawn (fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement) { - return static_cast<T *>(AActor::StaticSpawn (RUNTIME_CLASS(T), x, y, z, allowreplacement)); + return static_cast<T *>(AActor::StaticSpawn (RUNTIME_TEMPLATE_CLASS(T), x, y, z, allowreplacement)); } diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 40e919aae..97f76bce6 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -2040,7 +2040,7 @@ static int PatchCodePtrs (int dummy) if (!symname.CompareNoCase(MBFCodePointers[i].alias)) { symname = MBFCodePointers[i].name; - Printf("%s --> %s\n", MBFCodePointers[i].alias, MBFCodePointers[i].name); + Printf("%s --> %s\n", MBFCodePointers[i].alias, MBFCodePointers[i].name.GetChars()); } } diff --git a/src/dobject.h b/src/dobject.h index f19d84764..20426c72c 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -82,6 +82,7 @@ class PClassActor; #define RUNTIME_CLASS_CASTLESS(cls) (cls::RegistrationInfo.MyClass) // Passed a native class name, returns a PClass representing that class #define RUNTIME_CLASS(cls) ((cls::MetaClass *)RUNTIME_CLASS_CASTLESS(cls)) // Like above, but returns the true type of the meta object +#define RUNTIME_TEMPLATE_CLASS(cls) ((class cls::MetaClass *)RUNTIME_CLASS_CASTLESS(cls)) // RUNTIME_CLASS, but works with templated parameters on GCC #define NATIVE_TYPE(object) (object->StaticType()) // Passed an object, returns the type of the C++ class representing the object // Enumerations for the meta classes created by ClassReg::RegisterClass() diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 950e9bd7f..bf3a6773f 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -103,7 +103,7 @@ void DumpTypeTable() if (len > max) max = len; } - if (len < countof(lens)) + if (len < (int)countof(lens)) { lens[len]++; } @@ -114,7 +114,7 @@ void DumpTypeTable() Printf("Max bucket size: %d\n", max); Printf("Avg bucket size: %.2f\n", double(all) / used); int j,k; - for (k = k = countof(lens)-1; k > 0; --k) + for (k = countof(lens)-1; k > 0; --k) if (lens[k]) break; for (j = 0; j <= k; ++j) @@ -224,8 +224,8 @@ bool PType::IsMatch(intptr_t id1, intptr_t id2) const void PType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const { - id1 = NULL; - id2 = NULL; + id1 = 0; + id2 = 0; } //========================================================================== @@ -486,7 +486,7 @@ PPointer::PPointer(PType *pointsat) bool PPointer::IsMatch(intptr_t id1, intptr_t id2) const { - assert(id2 == NULL); + assert(id2 == 0); PType *pointat = (PType *)id1; return pointat == PointedType; @@ -733,7 +733,7 @@ PDynArray::PDynArray(PType *etype) bool PDynArray::IsMatch(intptr_t id1, intptr_t id2) const { - assert(id2 == NULL); + assert(id2 == 0); const PType *elemtype = (const PType *)id1; return elemtype == ElementType; diff --git a/src/dthinker.h b/src/dthinker.h index 32857d86b..e010e536d 100644 --- a/src/dthinker.h +++ b/src/dthinker.h @@ -121,10 +121,10 @@ public: template <class T> class TThinkerIterator : public FThinkerIterator { public: - TThinkerIterator (int statnum=MAX_STATNUM+1) : FThinkerIterator (RUNTIME_CLASS(T), statnum) + TThinkerIterator (int statnum=MAX_STATNUM+1) : FThinkerIterator (RUNTIME_TEMPLATE_CLASS(T), statnum) { } - TThinkerIterator (int statnum, DThinker *prev) : FThinkerIterator (RUNTIME_CLASS(T), statnum, prev) + TThinkerIterator (int statnum, DThinker *prev) : FThinkerIterator (RUNTIME_TEMPLATE_CLASS(T), statnum, prev) { } TThinkerIterator (const PClass *subclass, int statnum=MAX_STATNUM+1) : FThinkerIterator(subclass, statnum) diff --git a/src/farchive.h b/src/farchive.h index 6563bd15c..1a6f98ec5 100644 --- a/src/farchive.h +++ b/src/farchive.h @@ -272,7 +272,7 @@ inline FArchive &operator<< (FArchive &arc, PalEntry &p) template<class T> inline FArchive &operator<< (FArchive &arc, T* &object) { - return arc.SerializeObject ((DObject*&)object, RUNTIME_CLASS(T)); + return arc.SerializeObject ((DObject*&)object, RUNTIME_TEMPLATE_CLASS(T)); } FArchive &operator<< (FArchive &arc, PClass * &info); diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 3c868ffed..8f7342e05 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -1273,7 +1273,7 @@ bool AInventory::DoRespawn () void AInventory::GiveQuest (AActor *toucher) { int quest = GetClass()->GiveQuest; - if (quest > 0 && quest <= countof(QuestItemClasses)) + if (quest > 0 && quest <= (int)countof(QuestItemClasses)) { toucher->GiveInventoryType (QuestItemClasses[quest-1]); } diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index 4ca4a519c..13e802bef 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -240,7 +240,7 @@ DBaseStatusBar::DBaseStatusBar (int reltop, int hres, int vres) void DBaseStatusBar::Destroy () { - for (int i = 0; i < countof(Messages); ++i) + for (size_t i = 0; i < countof(Messages); ++i) { DHUDMessage *msg = Messages[i]; while (msg) @@ -342,7 +342,7 @@ void DBaseStatusBar::MultiplayerChanged () void DBaseStatusBar::Tick () { - for (int i = 0; i < countof(Messages); ++i) + for (size_t i = 0; i < countof(Messages); ++i) { DHUDMessage *msg = Messages[i]; DHUDMessage **prev = &Messages[i]; @@ -424,7 +424,7 @@ void DBaseStatusBar::AttachMessage (DHUDMessage *msg, DWORD id, int layer) DHUDMessage *DBaseStatusBar::DetachMessage (DHUDMessage *msg) { - for (int i = 0; i < countof(Messages); ++i) + for (size_t i = 0; i < countof(Messages); ++i) { DHUDMessage *probe = Messages[i]; DHUDMessage **prev = &Messages[i]; @@ -451,7 +451,7 @@ DHUDMessage *DBaseStatusBar::DetachMessage (DHUDMessage *msg) DHUDMessage *DBaseStatusBar::DetachMessage (DWORD id) { - for (int i = 0; i < countof(Messages); ++i) + for (size_t i = 0; i < countof(Messages); ++i) { DHUDMessage *probe = Messages[i]; DHUDMessage **prev = &Messages[i]; @@ -484,7 +484,7 @@ DHUDMessage *DBaseStatusBar::DetachMessage (DWORD id) void DBaseStatusBar::DetachAllMessages () { - for (int i = 0; i < countof(Messages); ++i) + for (size_t i = 0; i < countof(Messages); ++i) { DHUDMessage *probe = Messages[i]; @@ -1627,7 +1627,7 @@ void DBaseStatusBar::Serialize (FArchive &arc) } else { - for (int i = 0; i < countof(Messages); ++i) + for (size_t i = 0; i < countof(Messages); ++i) { arc << Messages[i]; } @@ -1639,7 +1639,7 @@ void DBaseStatusBar::ScreenSizeChanged () st_scale.Callback (); SB_state = screen->GetPageCount (); - for (int i = 0; i < countof(Messages); ++i) + for (size_t i = 0; i < countof(Messages); ++i) { DHUDMessage *message = Messages[i]; while (message != NULL) diff --git a/src/g_strife/a_thingstoblowup.cpp b/src/g_strife/a_thingstoblowup.cpp index b2898a235..018f4d589 100644 --- a/src/g_strife/a_thingstoblowup.cpp +++ b/src/g_strife/a_thingstoblowup.cpp @@ -35,7 +35,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveQuestItem) PARAM_INT(questitem); // Give one of these quest items to every player in the game - if (questitem >= 0 && questitem < countof(QuestItemClasses)) + if (questitem >= 0 && questitem < (int)countof(QuestItemClasses)) { for (int i = 0; i < MAXPLAYERS; ++i) { diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index dec0a4241..327632e55 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -352,7 +352,7 @@ void M_SetMenu(FName menu, int param) GameStartupInfo.Episode = -1; GameStartupInfo.PlayerClass = param == -1000? NULL : - param == -1? "Random" : GetPrintableDisplayName(PlayerClasses[param].Type); + param == -1? "Random" : GetPrintableDisplayName(PlayerClasses[param].Type).GetChars(); break; case NAME_Skillmenu: diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 3035749fe..0dbbf93af 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -2621,7 +2621,7 @@ AActor *AActor::TIDHash[128]; void AActor::ClearTIDHashes () { - memset(TIDHash, NULL, sizeof(TIDHash)); + memset(TIDHash, 0, sizeof(TIDHash)); } // diff --git a/src/p_user.cpp b/src/p_user.cpp index 61e9e6f11..a8b630c37 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -420,7 +420,7 @@ IMPLEMENT_CLASS(PClassPlayerPawn) PClassPlayerPawn::PClassPlayerPawn() { - for (int i = 0; i < countof(HexenArmor); ++i) + for (size_t i = 0; i < countof(HexenArmor); ++i) { HexenArmor[i] = 0; } @@ -433,7 +433,7 @@ void PClassPlayerPawn::Derive(PClass *newclass) assert(newclass->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); Super::Derive(newclass); PClassPlayerPawn *newp = static_cast<PClassPlayerPawn *>(newclass); - int i; + size_t i; newp->DisplayName = DisplayName; newp->SoundClass = SoundClass; diff --git a/src/r_data/sprites.cpp b/src/r_data/sprites.cpp index 6252e9575..3f5b7a522 100644 --- a/src/r_data/sprites.cpp +++ b/src/r_data/sprites.cpp @@ -952,7 +952,7 @@ void R_InitSprites () FString classface = basetype->Face; strcpy (skins[i].name, "Base"); - if (classface.IsEmpty() == NULL || strcmp(classface, "None") == 0) + if (classface.IsEmpty() || strcmp(classface, "None") == 0) { skins[i].face[0] = 'S'; skins[i].face[1] = 'T'; diff --git a/src/r_utility.cpp b/src/r_utility.cpp index b097149f5..c91da86a5 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -779,7 +779,7 @@ void R_SetupFrame (AActor *actor) { iview->nviewx = camera->x; iview->nviewy = camera->y; - iview->nviewz = camera->player ? camera->player->viewz : camera->z + camera->GetClass()->CameraHeight; + iview->nviewz = camera->player ? camera->player->viewz : camera->z + camera->GetCameraHeight(); viewsector = camera->Sector; r_showviewer = false; } diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index e4aac1a14..bd6b6f1e4 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -2280,7 +2280,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Log) { PARAM_ACTION_PROLOGUE; PARAM_STRING(text); - Printf("%s\n", text); + Printf("%s\n", text.GetChars()); ACTION_SET_RESULT(false); // Prints should never set the result for inventory state chains! return numret; } @@ -2737,7 +2737,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CountdownArg) PARAM_INT(argnum); PARAM_STATE_OPT(state) { state = self->FindState(NAME_Death); } - if (argnum > 0 && argnum < countof(self->args)) + if (argnum > 0 && argnum < (int)countof(self->args)) { if (!self->args[argnum]--) { @@ -3542,7 +3542,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag) } else { - Printf("Unknown flag '%s' in '%s'\n", flagname, cls->TypeName.GetChars()); + Printf("Unknown flag '%s' in '%s'\n", flagname.GetChars(), cls->TypeName.GetChars()); } return 0; } @@ -3598,7 +3598,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckFlag) } else { - Printf("Unknown flag '%s' in '%s'\n", flagname, cls->TypeName.GetChars()); + Printf("Unknown flag '%s' in '%s'\n", flagname.GetChars(), cls->TypeName.GetChars()); } return numret; } @@ -4092,7 +4092,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Turn) { PARAM_ACTION_PROLOGUE; - PARAM_ANGLE_OPT(angle); + PARAM_ANGLE_OPT(angle) { angle = 0; } self->angle += angle; return 0; } diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 7699750a2..8ef71dec1 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -831,7 +831,7 @@ ExpEmit FxMinusSign::Emit(VMFunctionBuilder *build) { assert(ValueType.Type == Operand->ValueType.Type); ExpEmit from = Operand->Emit(build); - assert(from.Konst != 0); + assert(from.Konst == 0); // Do it in-place. if (ValueType == VAL_Int) { @@ -929,7 +929,7 @@ ExpEmit FxUnaryNotBitwise::Emit(VMFunctionBuilder *build) assert(ValueType.Type == Operand->ValueType.Type); assert(ValueType == VAL_Int); ExpEmit from = Operand->Emit(build); - assert(from.Konst != 0); + assert(from.Konst == 0); // Do it in-place. build->Emit(OP_NOT, from.RegNum, from.RegNum, 0); return from; @@ -3507,23 +3507,32 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) assert(Self == NULL); unsigned i = 0; - build->Emit(OP_PARAMI, Special); // pass special number + build->Emit(OP_PARAMI, abs(Special)); // pass special number build->Emit(OP_PARAM, 0, REGT_POINTER, 0); // pass self if (ArgList != NULL) { for (; i < ArgList->Size(); ++i) { FxExpression *argex = (*ArgList)[i]; - assert(argex->ValueType == VAL_Int); - if (argex->isConstant()) + if (Special < 0 && i == 0) { - EmitConstantInt(build, argex->EvalExpression(NULL).GetInt()); + assert(argex->ValueType == VAL_Name); + assert(argex->isConstant()); + EmitConstantInt(build, -argex->EvalExpression(NULL).GetName()); } else { - ExpEmit arg(argex->Emit(build)); - build->Emit(OP_PARAM, 0, arg.RegType, arg.RegNum); - arg.Free(build); + assert(argex->ValueType == VAL_Int); + if (argex->isConstant()) + { + EmitConstantInt(build, argex->EvalExpression(NULL).GetInt()); + } + else + { + ExpEmit arg(argex->Emit(build)); + build->Emit(OP_PARAM, 0, arg.RegType, arg.RegNum); + arg.Free(build); + } } } } @@ -3995,11 +4004,11 @@ ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build) // Find the DecoFindMultiNameState function. If not found, create it and install it // in Actor. VMFunction *callfunc; - PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol(NAME_DecoNameToClass, false); + PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol(NAME_DecoFindMultiNameState, false); if (sym == NULL) { - PSymbolVMFunction *symfunc = new PSymbolVMFunction(NAME_DecoNameToClass); - VMNativeFunction *calldec = new VMNativeFunction(DecoFindMultiNameState, NAME_DecoNameToClass); + PSymbolVMFunction *symfunc = new PSymbolVMFunction(NAME_DecoFindMultiNameState); + VMNativeFunction *calldec = new VMNativeFunction(DecoFindMultiNameState, NAME_DecoFindMultiNameState); symfunc->Function = calldec; sym = symfunc; RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index 8f4470058..576aa72b1 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -88,7 +88,7 @@ static PClassActor *FindClassTentative(const char *name, PClass *ancestor) assert(cls != NULL); // cls can not be NULL here if (!cls->IsDescendantOf(ancestor)) { - I_Error("%s does not inherit from %s\n", name, ancestor); + I_Error("%s does not inherit from %s\n", name, ancestor->TypeName.GetChars()); } return static_cast<PClassActor *>(cls); } diff --git a/src/zscript/vmbuilder.cpp b/src/zscript/vmbuilder.cpp index 85e8c0469..4cf613d8f 100644 --- a/src/zscript/vmbuilder.cpp +++ b/src/zscript/vmbuilder.cpp @@ -446,7 +446,7 @@ size_t VMFunctionBuilder::Emit(int opcode, int opa, VM_SHALF opbc) { assert(opcode >= 0 && opcode < NUM_OPS); assert(opa >= 0 && opa <= 255); - assert(opbc >= -32768 && opbc <= 32767); + //assert(opbc >= -32768 && opbc <= 32767); always true due to parameter's width VMOP op; op.op = opcode; op.a = opa; diff --git a/src/zscript/vmdisasm.cpp b/src/zscript/vmdisasm.cpp index 04c3bbb9c..b6531e85b 100644 --- a/src/zscript/vmdisasm.cpp +++ b/src/zscript/vmdisasm.cpp @@ -157,7 +157,7 @@ void VMDumpConstants(FILE *out, const VMScriptFunction *func) { for (j = 0, k = i; j < 4 && k < func->NumKonstA; j++, k += kk) { - mysnprintf(tmp, countof(tmp), "%3d. %p:%d", k, func->KonstA[k], func->KonstATags()[k]); + mysnprintf(tmp, countof(tmp), "%3d. %p:%d", k, func->KonstA[k].v, func->KonstATags()[k]); printf_wrapper(out, "%-20s", tmp); } printf_wrapper(out, "\n"); diff --git a/src/zscript/vmexec.h b/src/zscript/vmexec.h index 71d71f065..b7e3bc374 100644 --- a/src/zscript/vmexec.h +++ b/src/zscript/vmexec.h @@ -1264,7 +1264,7 @@ begin: c = 0; } reg.a[a] = (VM_UBYTE *)reg.a[B] + c; - reg.atag[a] = c == 0 ? reg.atag[B] : ATAG_GENERIC; + reg.atag[a] = c == 0 ? reg.atag[B] : (int)ATAG_GENERIC; NEXTOP; OP(ADDA_RK): ASSERTA(a); ASSERTA(B); ASSERTKD(C); diff --git a/src/zscript/zcc_parser.cpp b/src/zscript/zcc_parser.cpp index 32816ec0c..3b31788db 100644 --- a/src/zscript/zcc_parser.cpp +++ b/src/zscript/zcc_parser.cpp @@ -168,7 +168,8 @@ static void DoParse(const char *filename) failed = false; #ifdef _DEBUG FILE *f = fopen("trace.txt", "w"); - ZCCParseTrace(f, ""); + char prompt = '\0'; + ZCCParseTrace(f, &prompt); #endif ZCCParseState state(sc); @@ -232,12 +233,14 @@ static void DoParse(const char *filename) FString ast = ZCC_PrintAST(state.TopNode); FString astfile = ExtractFileBase(filename, false); astfile << ".ast"; +#ifdef _DEBUG f = fopen(astfile, "w"); if (f != NULL) { fputs(ast.GetChars(), f); fclose(f); } +#endif } CCMD(parse) @@ -255,7 +258,7 @@ static FString ZCCTokenName(int terminal) return "end of file"; } int sc_token; - if (terminal > 0 && terminal < countof(BackTokenMap)) + if (terminal > 0 && terminal < (int)countof(BackTokenMap)) { sc_token = BackTokenMap[terminal]; if (sc_token == 0) diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 07012e73f..a6c7bd1c5 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -300,13 +300,13 @@ ACTOR Actor native //: Thinker action native A_TransferPointer(int ptr_source, int ptr_recepient, int sourcefield, int recepientfield=AAPTR_DEFAULT, int flags=0); action native A_CopyFriendliness(int ptr_source = AAPTR_MASTER); - action native ACS_NamedExecute(string script, int mapnum=0, int arg1=0, int arg2=0, int arg3=0); - action native ACS_NamedSuspend(string script, int mapnum=0); - action native ACS_NamedTerminate(string script, int mapnum=0); - action native ACS_NamedLockedExecute(string script, int mapnum=0, int arg1=0, int arg2=0, int lock=0); - action native ACS_NamedLockedExecuteDoor(string script, int mapnum=0, int arg1=0, int arg2=0, int lock=0); - action native ACS_NamedExecuteWithResult(string script, int arg1=0, int arg2=0, int arg3=0, int arg4=0); - action native ACS_NamedExecuteAlways(string script, int mapnum=0, int arg1=0, int arg2=0, int arg3=0); + action native ACS_NamedExecute(name script, int mapnum=0, int arg1=0, int arg2=0, int arg3=0); + action native ACS_NamedSuspend(name script, int mapnum=0); + action native ACS_NamedTerminate(name script, int mapnum=0); + action native ACS_NamedLockedExecute(name script, int mapnum=0, int arg1=0, int arg2=0, int lock=0); + action native ACS_NamedLockedExecuteDoor(name script, int mapnum=0, int arg1=0, int arg2=0, int lock=0); + action native ACS_NamedExecuteWithResult(name script, int arg1=0, int arg2=0, int arg3=0, int arg4=0); + action native ACS_NamedExecuteAlways(name script, int mapnum=0, int arg1=0, int arg2=0, int arg3=0); States { From c1aefec1e30702d98a03981937c48753ddd1d357 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Thu, 18 Oct 2012 03:32:00 +0000 Subject: [PATCH 054/232] - Redo one GCC fix to make it compatible with VC++. SVN r3894 (scripting) --- src/dobject.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dobject.h b/src/dobject.h index 20426c72c..783b8bb5b 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -82,7 +82,7 @@ class PClassActor; #define RUNTIME_CLASS_CASTLESS(cls) (cls::RegistrationInfo.MyClass) // Passed a native class name, returns a PClass representing that class #define RUNTIME_CLASS(cls) ((cls::MetaClass *)RUNTIME_CLASS_CASTLESS(cls)) // Like above, but returns the true type of the meta object -#define RUNTIME_TEMPLATE_CLASS(cls) ((class cls::MetaClass *)RUNTIME_CLASS_CASTLESS(cls)) // RUNTIME_CLASS, but works with templated parameters on GCC +#define RUNTIME_TEMPLATE_CLASS(cls) ((typename cls::MetaClass *)RUNTIME_CLASS_CASTLESS(cls)) // RUNTIME_CLASS, but works with templated parameters on GCC #define NATIVE_TYPE(object) (object->StaticType()) // Passed an object, returns the type of the C++ class representing the object // Enumerations for the meta classes created by ClassReg::RegisterClass() From 2c92941f6b8a16b73ca485868dd1be6dba6705b2 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Thu, 18 Oct 2012 04:04:33 +0000 Subject: [PATCH 055/232] - Fixed: FxCompareRel::Emit() generated broken code for floating point operands. SVN r3895 (scripting) --- src/thingdef/thingdef_expression.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 8ef71dec1..da3e7a17e 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -1566,7 +1566,7 @@ ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build) { OP_LT_RR, OP_LTF_RR, 0 }, // < { OP_LE_RR, OP_LEF_RR, 1 }, // > { OP_LT_RR, OP_LTF_RR, 1 }, // >= - { OP_LE_RR, OP_LE_RR, 0 } // <= + { OP_LE_RR, OP_LEF_RR, 0 } // <= }; int instr, check, index; @@ -1591,7 +1591,7 @@ ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build) { op1.Free(build); } - ExpEmit to(build, op1.RegType); + ExpEmit to(build, REGT_INT); // See FxUnaryNotBoolean for comments, since it's the same thing. build->Emit(OP_LI, to.RegNum, 0, 0); From 47eec0b2758e3b09271c47d1898a24c721558a29 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sun, 21 Oct 2012 03:46:17 +0000 Subject: [PATCH 056/232] - Added tracking of time spent specifically in running action functions. I feel kind of stupid about this now. I spent three days trying to figure out why the VC++ debug version was so slow. It turns out I had a conditional breakpoint set in a high-traffic area. D'oh! The rest of this stuff should get merged into trunk: - Fixed: Writing to debugfile uses the standard fprintf, which does not understand %td on VC++. - Fixed: Instead of crashing when a sprite has been scaled to 0, just don't draw it. SVN r3896 (scripting) --- src/dthinker.cpp | 4 +++- src/info.cpp | 7 ++++++- src/p_user.cpp | 4 ++-- src/r_things.cpp | 5 +++++ 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/dthinker.cpp b/src/dthinker.cpp index 85c5fb4bc..fa2e17a64 100644 --- a/src/dthinker.cpp +++ b/src/dthinker.cpp @@ -43,6 +43,7 @@ static cycle_t ThinkCycles; extern cycle_t BotSupportCycles; +extern cycle_t ActionCycles; extern int BotWTG; IMPLEMENT_CLASS (DThinker) @@ -409,6 +410,7 @@ void DThinker::RunThinkers () ThinkCycles.Reset(); BotSupportCycles.Reset(); + ActionCycles.Reset(); BotWTG = 0; ThinkCycles.Clock(); @@ -575,6 +577,6 @@ DThinker *FThinkerIterator::Next () ADD_STAT (think) { FString out; - out.Format ("Think time = %04.1f ms", ThinkCycles.TimeMS()); + out.Format ("Think time = %04.1f ms, Action = %04.1f ms", ThinkCycles.TimeMS(), ActionCycles.TimeMS()); return out; } diff --git a/src/info.cpp b/src/info.cpp index cbcfe89d6..361ba4bf0 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -50,6 +50,7 @@ #include "templates.h" #include "cmdlib.h" #include "g_level.h" +#include "stats.h" extern void LoadActors (); extern void InitBotStuff(); @@ -58,13 +59,17 @@ extern void ClearStrifeTypes(); TArray<PClassActor *> PClassActor::AllActorClasses; FRandom FState::pr_statetics; +cycle_t ActionCycles; + bool FState::CallAction(AActor *self, AActor *stateowner) { if (ActionFunc != NULL) { - VMFrameStack stack; + ActionCycles.Clock(); + static VMFrameStack stack; VMValue params[3] = { self, stateowner, VMValue(this, ATAG_STATE) }; stack.Call(ActionFunc, params, countof(params), NULL, 0, NULL); + ActionCycles.Unclock(); return true; } else diff --git a/src/p_user.cpp b/src/p_user.cpp index a8b630c37..c86cf186d 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -2192,8 +2192,8 @@ void P_PlayerThink (player_t *player) if (debugfile && !(player->cheats & CF_PREDICTING)) { - fprintf (debugfile, "tic %d for pl %td: (%d, %d, %d, %u) b:%02x p:%d y:%d f:%d s:%d u:%d\n", - gametic, player-players, player->mo->x, player->mo->y, player->mo->z, + fprintf (debugfile, "tic %d for pl %d: (%d, %d, %d, %u) b:%02x p:%d y:%d f:%d s:%d u:%d\n", + gametic, (int)(player-players), player->mo->x, player->mo->y, player->mo->z, player->mo->angle>>ANGLETOFINESHIFT, player->cmd.ucmd.buttons, player->cmd.ucmd.pitch, player->cmd.ucmd.yaw, player->cmd.ucmd.forwardmove, player->cmd.ucmd.sidemove, player->cmd.ucmd.upmove); diff --git a/src/r_things.cpp b/src/r_things.cpp index 680efeacb..74c32ba0f 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -326,6 +326,11 @@ void R_DrawVisSprite (vissprite_t *vis) fixed_t xiscale; ESPSResult mode; + if (vis->xscale == 0 || vis->yscale == 0) + { // scaled to 0; can't see + return; + } + dc_colormap = vis->Style.colormap; mode = R_SetPatchStyle (vis->Style.RenderStyle, vis->Style.alpha, vis->Translation, vis->FillColor); From d0c91083bcce4d76456fd54589de59793884b6a8 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 23 Oct 2012 03:19:17 +0000 Subject: [PATCH 057/232] - Re-jigged DoJump() to not be recursive so that 0-tic A_Jump* loops are no longer able to potentially blow up the stack. SVN r3902 (scripting) --- src/dobject.h | 1 + src/p_mobj.cpp | 9 +++++++++ src/thingdef/thingdef_codeptr.cpp | 10 +++++++++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/dobject.h b/src/dobject.h index 783b8bb5b..e96b7d6c2 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -205,6 +205,7 @@ enum EObjectFlags OF_JustSpawned = 1 << 8, // Thinker was spawned this tic OF_SerialSuccess = 1 << 9, // For debugging Serialize() calls OF_Sentinel = 1 << 10, // Object is serving as the sentinel in a ring list + OF_StateChanged = 1 << 11, // Used by A_Jump* functions to feed back to SetState() }; template<class T> class TObjPtr; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 0dbbf93af..f0fcf9b46 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -482,7 +482,16 @@ bool AActor::SetState (FState *newstate, bool nofunction) { // Check whether the called action function resulted in destroying the actor if (ObjectFlags & OF_EuthanizeMe) + { return false; + } + if (ObjectFlags & OF_StateChanged) + { // The action was an A_Jump-style function that wants to change the next state. + ObjectFlags &= ~OF_StateChanged; + newstate = state; + tics = 0; // make sure we loop and set the new state properly + continue; + } } newstate = newstate->GetNextState(); } while (tics == 0); diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index bd6b6f1e4..be9b47173 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -610,7 +610,15 @@ static void DoJump(AActor *self, AActor *stateowner, FState *callingstate, FStat } else if (callingstate == self->state) { - self->SetState(jumpto); + // Rather than using self->SetState(jumpto) to set the state, + // set the state directly. Since this function is only called by + // action functions, which are only called by SetState(), we + // know that somewhere above us in the stack, a SetState() + // call is waiting for us to return. We use the flag OF_StateChanged + // to cause it to bypass the normal next state mechanism and use + // the one we set here instead. + self->state = jumpto; + self->ObjectFlags |= OF_StateChanged; } else { // something went very wrong. This should never happen. From 0dae6527ad571598dfa6f69b174319bbcb432055 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 23 Oct 2012 03:19:26 +0000 Subject: [PATCH 058/232] - Fixed: FxCompareRel::Emit() needs to allocate the output register before freeing either of the operands. SVN r3903 (scripting) --- src/thingdef/thingdef_expression.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index da3e7a17e..2282949fe 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -1569,6 +1569,7 @@ ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build) { OP_LE_RR, OP_LEF_RR, 0 } // <= }; int instr, check, index; + ExpEmit to(build, REGT_INT); index = Operator == '<' ? 0 : Operator == '>' ? 1 : @@ -1591,7 +1592,6 @@ ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build) { op1.Free(build); } - ExpEmit to(build, REGT_INT); // See FxUnaryNotBoolean for comments, since it's the same thing. build->Emit(OP_LI, to.RegNum, 0, 0); From 79228e433130aada7527842920084a1bb80e3d80 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 23 Oct 2012 04:05:45 +0000 Subject: [PATCH 059/232] - Fixed: The disassembly for jmp opcodes displayed the wrong address. SVN r3904 (scripting) --- src/zscript/vmdisasm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zscript/vmdisasm.cpp b/src/zscript/vmdisasm.cpp index b6531e85b..fed5eb39a 100644 --- a/src/zscript/vmdisasm.cpp +++ b/src/zscript/vmdisasm.cpp @@ -209,7 +209,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction { case OP_JMP: case OP_TRY: - col = printf_wrapper(out, "%08x", i + 4 + (code[i].i24 << 2)); + col = printf_wrapper(out, "%08x", (i + 1 + code[i].i24) << 2); break; case OP_PARAMI: From 5c6bf0aeb4cc139d96442f9cc61f587911142003 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Thu, 25 Oct 2012 03:56:09 +0000 Subject: [PATCH 060/232] - Fixed: FxCompareEq::Emit() needs to allocate the output register before freeing the inputs. SVN r3906 (scripting) --- src/thingdef/thingdef_expression.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 2282949fe..671bb55a8 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -1719,6 +1719,8 @@ ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build) } assert(!op1.Konst); + ExpEmit to(build, op1.RegType); + instr = op1.RegType == REGT_INT ? OP_EQ_R : op1.RegType == REGT_FLOAT ? OP_EQF_R : OP_EQA_R; @@ -1731,7 +1733,6 @@ ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build) { instr += 1; } - ExpEmit to(build, op1.RegType); // See FxUnaryNotBoolean for comments, since it's the same thing. build->Emit(OP_LI, to.RegNum, 0, 0); From 1a02d163562215c87ec4d20d29c1c1a489924301 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 26 Oct 2012 04:04:06 +0000 Subject: [PATCH 061/232] - Added DecoFindSingleNameState for the extremely common case of finding a state with only one name in its label. This avoids the alloca and security cookie calls. - Consolidated lots of copy-pasted code in thingdef_expression.cpp to install helper functions into FindDecorateBuiltinFunction(). SVN r3907 (scripting) --- src/namedef.h | 1 + src/thingdef/thingdef_expression.cpp | 153 ++++++++++++++------------- src/zscript/vmexec.cpp | 2 +- 3 files changed, 80 insertions(+), 76 deletions(-) diff --git a/src/namedef.h b/src/namedef.h index 95a5aca9a..48d7a6a90 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -557,3 +557,4 @@ xx(DecoFRandom) xx(DecoCallLineSpecial) xx(DecoNameToClass) xx(DecoFindMultiNameState) +xx(DecoFindSingleNameState) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 671bb55a8..d1c225e90 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -97,6 +97,29 @@ void ExpEmit::Free(VMFunctionBuilder *build) } } +//========================================================================== +// +// FindDecorateBuiltinFunction +// +// Returns the symbol for a decorate utility function. If not found, create +// it and install it in Actor. +// +//========================================================================== + +static PSymbol *FindDecorateBuiltinFunction(FName funcname, VMNativeFunction::NativeCallType func) +{ + PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol(funcname, false); + if (sym == NULL) + { + PSymbolVMFunction *symfunc = new PSymbolVMFunction(funcname); + VMNativeFunction *calldec = new VMNativeFunction(func, funcname); + symfunc->Function = calldec; + sym = symfunc; + RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); + } + return sym; +} + //========================================================================== // // EvalExpression @@ -2485,18 +2508,10 @@ int DecoRandom(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, ExpEmit FxRandom::Emit(VMFunctionBuilder *build) { - // Find the DecoRandom function. If not found, create it and install it - // in Actor. + // Call DecoRandom to generate a random number. VMFunction *callfunc; - PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol(NAME_DecoRandom, false); - if (sym == NULL) - { - PSymbolVMFunction *symfunc = new PSymbolVMFunction(NAME_DecoRandom); - VMNativeFunction *calldec = new VMNativeFunction(DecoRandom, NAME_DecoRandom); - symfunc->Function = calldec; - sym = symfunc; - RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); - } + PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoRandom, DecoRandom); + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; @@ -2591,18 +2606,10 @@ int DecoFRandom(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) { - // Find the DecoFRandom function. If not found, create it and install it - // in Actor. + // Call the DecoFRandom function to generate a floating point random number.. VMFunction *callfunc; - PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol(NAME_DecoFRandom, false); - if (sym == NULL) - { - PSymbolVMFunction *symfunc = new PSymbolVMFunction(NAME_DecoFRandom); - VMNativeFunction *calldec = new VMNativeFunction(DecoFRandom, NAME_DecoFRandom); - symfunc->Function = calldec; - sym = symfunc; - RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); - } + PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoFRandom, DecoFRandom); + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; @@ -2681,18 +2688,10 @@ ExpVal FxRandom2::EvalExpression (AActor *self) ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) { - // Find the DecoRandom function. If not found, create it and install it - // in Actor. + // Call the DecoRandom function to generate the random number. VMFunction *callfunc; - PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol(NAME_DecoRandom, false); - if (sym == NULL) - { - PSymbolVMFunction *symfunc = new PSymbolVMFunction(NAME_DecoRandom); - VMNativeFunction *calldec = new VMNativeFunction(DecoRandom, NAME_DecoRandom); - symfunc->Function = calldec; - sym = symfunc; - RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); - } + PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoRandom, DecoRandom); + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; @@ -3537,18 +3536,10 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) } } } - // Find the DecoCallLineSpecial function. If not found, create it and install it - // in Actor. + // Call the DecoCallLineSpecial function to perform the desired special. VMFunction *callfunc; - PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol(NAME_DecoCallLineSpecial, false); - if (sym == NULL) - { - PSymbolVMFunction *symfunc = new PSymbolVMFunction(NAME_DecoCallLineSpecial); - VMNativeFunction *calldec = new VMNativeFunction(DecoCallLineSpecial, NAME_DecoCallLineSpecial); - symfunc->Function = calldec; - sym = symfunc; - RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); - } + PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoCallLineSpecial, DecoCallLineSpecial); + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; @@ -3802,18 +3793,10 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build) build->Emit(OP_PARAM, 0, clsname.RegType, clsname.RegNum); build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(const_cast<PClass *>(desttype), ATAG_OBJECT)); - // Find the DecoNameToClass function. If not found, create it and install it - // in Actor. + // Call the DecoNameToClass function to convert from 'name' to class. VMFunction *callfunc; - PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol(NAME_DecoNameToClass, false); - if (sym == NULL) - { - PSymbolVMFunction *symfunc = new PSymbolVMFunction(NAME_DecoNameToClass); - VMNativeFunction *calldec = new VMNativeFunction(DecoNameToClass, NAME_DecoNameToClass); - symfunc->Function = calldec; - sym = symfunc; - RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); - } + PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoNameToClass, DecoNameToClass); + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; @@ -3964,18 +3947,8 @@ ExpVal FxMultiNameState::EvalExpression (AActor *self) return ret; } -int DecoFindMultiNameState(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) +static int DoFindState(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, FName *names, int numnames) { - assert(numparam > 1); - assert(numret == 1); - assert(ret->RegType == REGT_POINTER); - - FName *names = (FName *)alloca((numparam - 1) * sizeof(FName)); - for (int i = 1; i < numparam; ++i) - { - PARAM_NAME_AT(i, zaname); - names[i - 1] = zaname; - } PARAM_OBJECT_AT(0, self, AActor); FState *state = self->GetClass()->FindState(numparam - 1, names); if (state == NULL) @@ -3991,6 +3964,34 @@ int DecoFindMultiNameState(VMFrameStack *stack, VMValue *param, int numparam, VM } ret->SetPointer(state, ATAG_STATE); return 1; + +} + +// Find a state with any number of dots in its name. +int DecoFindMultiNameState(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) +{ + assert(numparam > 1); + assert(numret == 1); + assert(ret->RegType == REGT_POINTER); + + FName *names = (FName *)alloca((numparam - 1) * sizeof(FName)); + for (int i = 1; i < numparam; ++i) + { + PARAM_NAME_AT(i, zaname); + names[i - 1] = zaname; + } + return DoFindState(stack, param, numparam, ret, names, numparam - 1); +} + +// Find a state without any dots in its name. +int DecoFindSingleNameState(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) +{ + assert(numparam == 2); + assert(numret == 1); + assert(ret->RegType == REGT_POINTER); + + PARAM_NAME_AT(1, zaname); + return DoFindState(stack, param, numparam, ret, &zaname, 1); } ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build) @@ -4002,18 +4003,20 @@ ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build) EmitConstantInt(build, names[i]); } - // Find the DecoFindMultiNameState function. If not found, create it and install it - // in Actor. + // For one name, use the DecoFindSingleNameState function. For more than + // one name, use the DecoFindMultiNameState function. VMFunction *callfunc; - PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol(NAME_DecoFindMultiNameState, false); - if (sym == NULL) + PSymbol *sym; + + if (names.Size() == 1) { - PSymbolVMFunction *symfunc = new PSymbolVMFunction(NAME_DecoFindMultiNameState); - VMNativeFunction *calldec = new VMNativeFunction(DecoFindMultiNameState, NAME_DecoFindMultiNameState); - symfunc->Function = calldec; - sym = symfunc; - RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); + sym = FindDecorateBuiltinFunction(NAME_DecoFindSingleNameState, DecoFindSingleNameState); } + else + { + sym = FindDecorateBuiltinFunction(NAME_DecoFindMultiNameState, DecoFindMultiNameState); + } + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; diff --git a/src/zscript/vmexec.cpp b/src/zscript/vmexec.cpp index 8ad349cf7..ceecf5e01 100644 --- a/src/zscript/vmexec.cpp +++ b/src/zscript/vmexec.cpp @@ -131,8 +131,8 @@ void VMSelectEngine(EVMEngine engine) #ifdef NDEBUG VMExec = VMExec_Unchecked::Exec; #else - VMExec = VMExec_Checked::Exec; #endif + VMExec = VMExec_Checked::Exec; break; case VMEngine_Unchecked: VMExec = VMExec_Unchecked::Exec; From aade32a749c3509d198e445e0b455e4c27ee6e6f Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 26 Oct 2012 19:52:24 +0000 Subject: [PATCH 062/232] - Add PClass::AllClasses to the list of root items for the GC. Failure to do so will cause any actors with names that conflicted with preceding actors from being freed, even though they can still be accessed via PClassActor::AllActorClasses, which gets iterated over in a number of places. (e.g. Zen Dynamics defines a Grenade actor, although there is one in zdoom.pk3 now. The Zen Dynamics' version would not go in the TypeTable, so it would be collected on map load, leading to a crash when attempts to access it through AllActorClasses are made.) SVN r3908 (scripting) --- src/dobjgc.cpp | 4 ++++ src/thingdef/thingdef_expression.cpp | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index 59e099006..05cc73aed 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -365,6 +365,10 @@ static void MarkRoot() } // Mark types TypeTable.Mark(); + for (unsigned int i = 0; i < PClass::AllClasses.Size(); ++i) + { + Mark(PClass::AllClasses[i]); + } // Mark bot stuff. Mark(bglobal.firstthing); Mark(bglobal.body1); diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index d1c225e90..2ebea2a46 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3964,7 +3964,6 @@ static int DoFindState(VMFrameStack *stack, VMValue *param, int numparam, VMRetu } ret->SetPointer(state, ATAG_STATE); return 1; - } // Find a state with any number of dots in its name. From 83480fd7f3779b73df41731ee2e9a4615101af25 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 26 Oct 2012 20:12:55 +0000 Subject: [PATCH 063/232] - Fixed: A_CustomMissile's pitch argument is an angle, not an int. SVN r3909 (scripting) --- src/thingdef/thingdef_codeptr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index be9b47173..e1d9f230d 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -989,7 +989,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile) PARAM_INT_OPT (spawnofs_xy) { spawnofs_xy = 0; } PARAM_ANGLE_OPT (angle) { angle = 0; } PARAM_INT_OPT (flags) { flags = 0; } - PARAM_INT_OPT (pitch) { pitch = 0; } + PARAM_ANGLE_OPT (pitch) { pitch = 0; } int aimmode = flags & CMF_AIMMODE; From ac251cfe80f5036ddb339715c1713c7ca0b358d2 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 26 Oct 2012 20:27:49 +0000 Subject: [PATCH 064/232] - Fixed: FxCompareEq::Emit()'s output must be in an integer register. SVN r3910 (scripting) --- src/thingdef/thingdef_expression.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 2ebea2a46..ea5c5005e 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -1742,7 +1742,7 @@ ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build) } assert(!op1.Konst); - ExpEmit to(build, op1.RegType); + ExpEmit to(build, REGT_INT); instr = op1.RegType == REGT_INT ? OP_EQ_R : op1.RegType == REGT_FLOAT ? OP_EQF_R : From 110c253854b54b43a4daa1c8ef4f86aa8cc0ded8 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 26 Oct 2012 22:56:50 +0000 Subject: [PATCH 065/232] - Silence GCC warning stuffs. SVN r3911 (scripting) --- src/zscript/vmexec.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/zscript/vmexec.h b/src/zscript/vmexec.h index b7e3bc374..ff9b471d5 100644 --- a/src/zscript/vmexec.h +++ b/src/zscript/vmexec.h @@ -718,7 +718,7 @@ begin: reg.d[a] = reg.d[B] << reg.d[C]; NEXTOP; OP(SLL_RI): - ASSERTD(a); ASSERTD(B); assert(0 <= C && C <= 31); + ASSERTD(a); ASSERTD(B); assert(C <= 31); reg.d[a] = reg.d[B] << C; NEXTOP; OP(SLL_KR): @@ -731,7 +731,7 @@ begin: reg.d[a] = (unsigned)reg.d[B] >> reg.d[C]; NEXTOP; OP(SRL_RI): - ASSERTD(a); ASSERTD(B); assert(0 <= C && C <= 31); + ASSERTD(a); ASSERTD(B); assert(C <= 31); reg.d[a] = (unsigned)reg.d[B] >> C; NEXTOP; OP(SRL_KR): @@ -744,7 +744,7 @@ begin: reg.d[a] = reg.d[B] >> reg.d[C]; NEXTOP; OP(SRA_RI): - ASSERTD(a); ASSERTD(B); assert(0 <= C && C <= 31); + ASSERTD(a); ASSERTD(B); assert(C <= 31); reg.d[a] = reg.d[B] >> C; NEXTOP; OP(SRA_KR): From 5b8a54e5ee8c0e44ebfb62cfc7190c81b3f8a60c Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 27 Oct 2012 01:37:10 +0000 Subject: [PATCH 066/232] - Fixed: Inventory's AltHUDIcon must be initialized to null, not invalid. SVN r3912 (scripting) --- src/g_shared/a_pickups.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 8f7342e05..f2f5b0857 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -27,7 +27,7 @@ IMPLEMENT_CLASS(PClassInventory) PClassInventory::PClassInventory() { GiveQuest = 0; - AltHUDIcon.SetInvalid(); + AltHUDIcon.SetNull(); } void PClassInventory::Derive(PClass *newclass) From 71712815077c646e34ef119b73dbe7cfdf942f86 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 27 Oct 2012 02:04:35 +0000 Subject: [PATCH 067/232] - Compatibility fix: Classes redefined in DECORATE should cause the newer one to replace the older one in the type table. SVN r3913 (scripting) --- src/dobjtype.cpp | 26 ++++++++++++++++++++++++++ src/dobjtype.h | 1 + 2 files changed, 27 insertions(+) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index bf3a6773f..9420a939f 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -1180,6 +1180,7 @@ void PClass::InsertIntoHash () { // This type has already been inserted // ... but there is no need whatsoever to make it a fatal error! Printf (TEXTCOLOR_RED"Tried to register class '%s' more than once.\n", TypeName.GetChars()); + TypeTable.ReplaceType(this, found, bucket); } else { @@ -1471,6 +1472,31 @@ PType *FTypeTable::FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, si return NULL; } +//========================================================================== +// +// FTypeTable :: ReplaceType +// +// Replaces an existing type in the table with a new version of the same +// type. For use when redefining actors in DECORATE. Does nothing if the +// old version is not in the table. +// +//========================================================================== + +void FTypeTable::ReplaceType(PType *newtype, PType *oldtype, size_t bucket) +{ + for (PType **type_p = &TypeHash[bucket]; *type_p != NULL; type_p = &(*type_p)->HashNext) + { + PType *type = *type_p; + if (type == oldtype) + { + newtype->HashNext = type->HashNext; + type->HashNext = NULL; + *type_p = newtype; + break; + } + } +} + //========================================================================== // // FTypeTable :: AddType - Fully Parameterized Version diff --git a/src/dobjtype.h b/src/dobjtype.h index a3b41e12d..b04f7fce5 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -561,6 +561,7 @@ struct FTypeTable PType *TypeHash[HASH_SIZE]; PType *FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, size_t *bucketnum); + void ReplaceType(PType *newtype, PType *oldtype, size_t bucket); void AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t parm2, size_t bucket); void AddType(PType *type); void Mark(); From e6b150bab9bd36f66573311dc509c6cb3d720f4b Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 27 Oct 2012 02:13:53 +0000 Subject: [PATCH 068/232] - Fixed: A_Explode should always perform the distance <= 0 check, not just when damage < 0. SVN r3914 (scripting) --- src/thingdef/thingdef_codeptr.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index e1d9f230d..f592fd75a 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -868,10 +868,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode) flags = !self->GetClass()->DontHurtShooter; alert = false; } - else - { - if (distance <= 0) distance = damage; - } + if (distance <= 0) distance = damage; + // NailBomb effect, from SMMU but not from its source code: instead it was implemented and // generalized from the documentation at http://www.doomworld.com/eternity/engine/codeptrs.html From be27e68fc4579ddc67d053e9675212dcd0c8b0e7 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 27 Oct 2012 02:37:40 +0000 Subject: [PATCH 069/232] - Fixed: A_BrainSpit's parameter is optional. SVN r3915 (scripting) --- src/g_doom/a_bossbrain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_doom/a_bossbrain.cpp b/src/g_doom/a_bossbrain.cpp index 7f0ecba15..59191032c 100644 --- a/src/g_doom/a_bossbrain.cpp +++ b/src/g_doom/a_bossbrain.cpp @@ -107,7 +107,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BrainDie) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BrainSpit) { PARAM_ACTION_PROLOGUE; - PARAM_CLASS(spawntype, AActor); + PARAM_CLASS_OPT(spawntype, AActor) { spawntype = NULL; } DSpotState *state = DSpotState::GetSpotState(); AActor *targ; From 31ab5ed8667272ec834d19f38898c1c61bf47fb5 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 27 Oct 2012 03:56:44 +0000 Subject: [PATCH 070/232] - Added zcc-parse.c dependency to CMakeLists.txt SVN r3916 (scripting) --- src/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a96c5d097..fe982109d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -914,6 +914,7 @@ add_executable( zdoom WIN32 ) set_source_files_properties( xlat/parse_xlat.cpp PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c" ) +set_source_files_properties( zscript/zcc_parser.cpp PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.c" ) set_source_files_properties( sc_man.cpp PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h" ) if(${CMAKE_SYSTEM_NAME} STREQUAL "SunOS") From 29bc9cbf35d150261652729e5336dc9c3b28ea7b Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sun, 28 Oct 2012 01:16:01 +0000 Subject: [PATCH 071/232] - Change the formatting for floating immediates in the dissasembly to %g. SVN r3917 (scripting) --- src/zscript/vmdisasm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zscript/vmdisasm.cpp b/src/zscript/vmdisasm.cpp index fed5eb39a..81eb50bba 100644 --- a/src/zscript/vmdisasm.cpp +++ b/src/zscript/vmdisasm.cpp @@ -370,7 +370,7 @@ static int print_reg(FILE *out, int col, int arg, int mode, int immshift, const case MODE_KF: if (func != NULL) { - return col+printf_wrapper(out, "%f", func->KonstF[arg]); + return col+printf_wrapper(out, "%g", func->KonstF[arg]); } return col+printf_wrapper(out, "kf%d", arg); case MODE_KS: From 5e184260aca4784323701f3e9baed23b0286cde0 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sun, 28 Oct 2012 01:26:10 +0000 Subject: [PATCH 072/232] - Fixed: FastProjectile's missile height needs to be initialized to 0. SVN r3918 (scripting) --- wadsrc/static/actors/shared/sharedmisc.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/wadsrc/static/actors/shared/sharedmisc.txt b/wadsrc/static/actors/shared/sharedmisc.txt index 6a71025d2..a9ede0245 100644 --- a/wadsrc/static/actors/shared/sharedmisc.txt +++ b/wadsrc/static/actors/shared/sharedmisc.txt @@ -150,6 +150,7 @@ ACTOR RandomSpawner native ACTOR FastProjectile native { Projectile + MissileHeight 0 } // Sector flag setter ------------------------------------------------------ From 6e885293248111229db96cc61eaa70cd5b356da0 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sun, 28 Oct 2012 04:36:52 +0000 Subject: [PATCH 073/232] - Added a RETI instruction for returning 15-bit signed immediate values. - Changed Actor's Damage property into an actual function. All access to the damage property must now be done through GetMissileDamage. actor->GetMissileDamage(0, 1) is equivalent to the former actor->Damage, for the case where actor->Damage was not an expression. (I suppose I will probably need to make a thunk for DECORATE expressions that want to read it.) - Cleaned up some decorate expression evaluation functions that are no longer used. SVN r3919 (scripting) --- src/actor.h | 2 +- src/d_dehacked.cpp | 2 +- src/g_doom/a_bossbrain.cpp | 2 +- src/g_doom/a_fatso.cpp | 2 +- src/g_doom/a_lostsoul.cpp | 2 +- src/g_heretic/a_ironlich.cpp | 2 +- src/g_hexen/a_magelightning.cpp | 2 +- src/info.cpp | 3 + src/p_acs.cpp | 4 +- src/p_mobj.cpp | 28 +++-- src/thingdef/olddecorations.cpp | 2 +- src/thingdef/thingdef.cpp | 81 +++++++++++-- src/thingdef/thingdef.h | 54 +++------ src/thingdef/thingdef_exp.h | 22 ++++ src/thingdef/thingdef_expression.cpp | 175 +++++++++------------------ src/thingdef/thingdef_parse.cpp | 24 ++-- src/thingdef/thingdef_properties.cpp | 6 +- src/zscript/vmbuilder.cpp | 21 ++++ src/zscript/vmbuilder.h | 1 + src/zscript/vmdisasm.cpp | 17 +++ src/zscript/vmexec.h | 12 ++ src/zscript/vmops.h | 1 + wadsrc/static/actors/actor.txt | 2 +- 23 files changed, 271 insertions(+), 196 deletions(-) diff --git a/src/actor.h b/src/actor.h index 995c4d073..970397d15 100644 --- a/src/actor.h +++ b/src/actor.h @@ -797,7 +797,7 @@ public: fixed_t velx, vely, velz; // velocity SDWORD tics; // state tic counter FState *state; - SDWORD Damage; // For missiles and monster railgun + VMFunction *Damage; // For missiles and monster railgun int projectileKickback; DWORD flags; DWORD flags2; // Heretic flags diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 97f76bce6..c1e3b2800 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -852,7 +852,7 @@ static int PatchThing (int thingy) } else if (linelen == 14 && stricmp (Line1, "Missile damage") == 0) { - info->Damage = val; + info->Damage = CreateDamageFunction(val); } else if (linelen == 5) { diff --git a/src/g_doom/a_bossbrain.cpp b/src/g_doom/a_bossbrain.cpp index 59191032c..51d7f0e62 100644 --- a/src/g_doom/a_bossbrain.cpp +++ b/src/g_doom/a_bossbrain.cpp @@ -47,7 +47,7 @@ static void BrainishExplosion (fixed_t x, fixed_t y, fixed_t z) boom->SetState (state); } boom->effects = 0; - boom->Damage = 0; // disables collision detection which is not wanted here + boom->Damage = NULL; // disables collision detection which is not wanted here boom->tics -= pr_brainscream() & 7; if (boom->tics < 1) boom->tics = 1; diff --git a/src/g_doom/a_fatso.cpp b/src/g_doom/a_fatso.cpp index 67ae803b9..015e82916 100644 --- a/src/g_doom/a_fatso.cpp +++ b/src/g_doom/a_fatso.cpp @@ -144,7 +144,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Mushroom) if (n == 0) { - n = self->Damage; // GetMissileDamage (0, 1); + n = self->GetMissileDamage(0, 1); } if (spawntype == NULL) { diff --git a/src/g_doom/a_lostsoul.cpp b/src/g_doom/a_lostsoul.cpp index 887f2d9d7..a8fb44c0a 100644 --- a/src/g_doom/a_lostsoul.cpp +++ b/src/g_doom/a_lostsoul.cpp @@ -65,7 +65,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BetaSkullAttack) return 0; S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); A_FaceTarget(self); - damage = (pr_oldsoul()%8+1)*self->Damage; + damage = (pr_oldsoul()%8+1)*self->GetMissileDamage(0,1); P_DamageMobj(self->target, self, self, damage, NAME_None); return 0; } diff --git a/src/g_heretic/a_ironlich.cpp b/src/g_heretic/a_ironlich.cpp index 0a345d2a6..852f3d258 100644 --- a/src/g_heretic/a_ironlich.cpp +++ b/src/g_heretic/a_ironlich.cpp @@ -116,7 +116,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack) fire->velx = baseFire->velx; fire->vely = baseFire->vely; fire->velz = baseFire->velz; - fire->Damage = 0; + fire->Damage = NULL; fire->health = (i+1) * 2; P_CheckMissileSpawn (fire); } diff --git a/src/g_hexen/a_magelightning.cpp b/src/g_hexen/a_magelightning.cpp index 7010aaceb..0a31ef143 100644 --- a/src/g_hexen/a_magelightning.cpp +++ b/src/g_hexen/a_magelightning.cpp @@ -356,7 +356,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LastZap) { mo->SetState (mo->FindState (NAME_Death)); mo->velz = 40*FRACUNIT; - mo->Damage = 0; + mo->Damage = NULL; } return 0; } diff --git a/src/info.cpp b/src/info.cpp index 361ba4bf0..523855084 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -302,6 +302,9 @@ size_t PClassActor::PropagateMark() GC::Mark(OwnedStates[i].ActionFunc); } } + // Mark damage function + GC::Mark(((AActor *)Defaults)->Damage); + // marked += ActorInfo->NumOwnedStates * sizeof(FState); return Super::PropagateMark(); } diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 668c4dc1b..81da86259 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -2832,7 +2832,7 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value) break; case APROP_Damage: - actor->Damage = value; + actor->Damage = CreateDamageFunction(value); break; case APROP_Alpha: @@ -2994,7 +2994,7 @@ int DLevelScript::GetActorProperty (int tid, int property) { case APROP_Health: return actor->health; case APROP_Speed: return actor->Speed; - case APROP_Damage: return actor->Damage; // Should this call GetMissileDamage() instead? + case APROP_Damage: return actor->GetMissileDamage(0,1); case APROP_DamageFactor:return actor->DamageFactor; case APROP_Alpha: return actor->alpha; case APROP_RenderStyle: for (int style = STYLE_None; style < STYLE_Count; ++style) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f0fcf9b46..458ed36f0 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -136,6 +136,7 @@ IMPLEMENT_POINTY_CLASS (AActor) DECLARE_POINTER (LastHeard) DECLARE_POINTER (master) DECLARE_POINTER (Poisoner) + DECLARE_POINTER (Damage) END_POINTERS AActor::~AActor () @@ -2778,21 +2779,34 @@ CCMD(utid) int AActor::GetMissileDamage (int mask, int add) { - if ((Damage & 0xC0000000) == 0x40000000) - { - return EvalExpressionI (Damage & 0x3FFFFFFF, this); - } - if (Damage == 0) + if (Damage == NULL) { return 0; } + VMFrameStack stack; + VMValue param = this; + VMReturn results[2]; + + int amount, calculated = false; + + results[0].IntAt(&amount); + results[1].IntAt(&calculated); + + if (stack.Call(Damage, ¶m, 1, results, 2) < 1) + { // No results + return 0; + } + if (calculated) + { + return amount; + } else if (mask == 0) { - return add * Damage; + return add * amount; } else { - return ((pr_missiledamage() & mask) + add) * Damage; + return ((pr_missiledamage() & mask) + add) * amount; } } diff --git a/src/thingdef/olddecorations.cpp b/src/thingdef/olddecorations.cpp index 78d890be0..8c1da024c 100644 --- a/src/thingdef/olddecorations.cpp +++ b/src/thingdef/olddecorations.cpp @@ -495,7 +495,7 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, else if (def == DEF_Projectile && sc.Compare ("Damage")) { sc.MustGetNumber (); - defaults->Damage = sc.Number; + defaults->Damage = CreateDamageFunction(sc.Number); } else if (def == DEF_Projectile && sc.Compare ("DamageType")) { diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index b764e48ab..d162a9f10 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -261,6 +261,17 @@ void FinishActor(const FScriptPosition &sc, PClassActor *info, Baggage &bag) // //========================================================================== +static void DumpFunction(FILE *dump, VMScriptFunction *sfunc, const char *label, int labellen) +{ + const char *marks = "======================================================="; + fprintf(dump, "\n%.*s %s %.*s", MAX(3, 38 - labellen / 2), marks, label, MAX(3, 38 - labellen / 2), marks); + fprintf(dump, "\nInteger regs: %-3d Float regs: %-3d Address regs: %-3d String regs: %-3d\nStack size: %d\n", + sfunc->NumRegD, sfunc->NumRegF, sfunc->NumRegA, sfunc->NumRegS, sfunc->MaxParam); + VMDumpConstants(dump, sfunc); + fprintf(dump, "\nDisassembly @ %p:\n", sfunc->Code); + VMDisasm(dump, sfunc->Code, sfunc->CodeSize, sfunc); +} + static void FinishThingdef() { int errorcount = StateParams.ResolveAll(); @@ -305,17 +316,10 @@ static void FinishThingdef() sfunc->NumArgs = NAP; func = sfunc; #if 1 - const char *marks = "======================================================="; char label[64]; int labellen = mysnprintf(label, countof(label), "Function %s.States[%d] (*%d)", - tcall->ActorClass->TypeName.GetChars(), - tcall->FirstState, tcall->NumStates); - fprintf(dump, "\n%.*s %s %.*s", MAX(3, 38 - labellen / 2), marks, label, MAX(3, 38 - labellen / 2), marks); - fprintf(dump, "\nInteger regs: %-3d Float regs: %-3d Address regs: %-3d String regs: %-3d\nStack size: %d\n", - sfunc->NumRegD, sfunc->NumRegF, sfunc->NumRegA, sfunc->NumRegS, sfunc->MaxParam); - VMDumpConstants(dump, sfunc); - fprintf(dump, "\nDisassembly @ %p:\n", sfunc->Code); - VMDisasm(dump, sfunc->Code, sfunc->CodeSize, sfunc); + tcall->ActorClass->TypeName.GetChars(), tcall->FirstState, tcall->NumStates); + DumpFunction(dump, sfunc, label, labellen); codesize += sfunc->CodeSize; #endif } @@ -324,10 +328,6 @@ static void FinishThingdef() tcall->ActorClass->OwnedStates[tcall->FirstState + k].SetAction(func); } } -#if 1 - fprintf(dump, "\n*************************************************************************\n%i code bytes\n", codesize * 4); -#endif - fclose(dump); for (i = 0; i < PClassActor::AllActorClasses.Size(); i++) { @@ -348,7 +348,42 @@ static void FinishThingdef() errorcount++; continue; } + + if (def->Damage != NULL) + { + VMScriptFunction *sfunc; + FxDamageValue *dmg = (FxDamageValue *)def->Damage; + sfunc = dmg->GetFunction(); + if (sfunc == NULL) + { + FCompileContext ctx(ti, true); + dmg->Resolve(ctx); + VMFunctionBuilder buildit; + buildit.Registers[REGT_POINTER].Get(1); // The self pointer + dmg->Emit(&buildit); + sfunc = buildit.MakeFunction(); + sfunc->NumArgs = 1; + // Save this function in case this damage value was reused + // (which happens quite easily with inheritance). + dmg->SetFunction(sfunc); + } + def->Damage = sfunc; +#if 1 + if (sfunc != NULL) + { + char label[64]; + int labellen = mysnprintf(label, countof(label), "Function %s.Damage", + ti->TypeName.GetChars()); + DumpFunction(dump, sfunc, label, labellen); + codesize += sfunc->CodeSize; + } +#endif + } } +#if 1 + fprintf(dump, "\n*************************************************************************\n%i code bytes\n", codesize * 4); +#endif + fclose(dump); if (errorcount > 0) { I_Error("%d errors during actor postprocessing", errorcount); @@ -399,3 +434,23 @@ void LoadActors () // Base time: ~52 ms } + +//========================================================================== +// +// CreateDamageFunction +// +// Creates a damage function suitable for a constant, non-expressioned +// value. +// +//========================================================================== + +VMScriptFunction *CreateDamageFunction(int dmg) +{ + VMFunctionBuilder build; + build.Registers[REGT_POINTER].Get(1); // The self pointer + build.EmitRetInt(0, false, dmg); + build.EmitRetInt(1, true, 0); + VMScriptFunction *sfunc = build.MakeFunction(); + sfunc->NumArgs = 1; + return sfunc; +} diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index 68d16e8fc..2eb84b002 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -141,8 +141,8 @@ public: void Clear(); int Add(FxExpression *x, PClassActor *o, bool c); int Reserve(int num, PClassActor *cls); - void Set(int num, FxExpression *x, bool cloned = false); - void Copy(int dest, int src, int cnt); +// void Set(int num, FxExpression *x, bool cloned = false); +// void Copy(int dest, int src, int cnt); int ResolveAll(); FxExpression *Get(int no); unsigned int Size() { return expressions.Size(); } @@ -184,6 +184,14 @@ inline void ResetBaggage (Baggage *bag, PClassActor *stateclass) bag->statedef.MakeStateDefines(stateclass); } +//========================================================================== +// +// Damage function creation +// +//========================================================================== + +VMScriptFunction *CreateDamageFunction(int dmg); + //========================================================================== // // Action function lookup @@ -270,6 +278,7 @@ union FPropParam int i; float f; const char *s; + FxExpression *exp; }; typedef void (*PropHandler)(AActor *defaults, PClassActor *info, Baggage &bag, FPropParam *params); @@ -328,6 +337,9 @@ int MatchString (const char *in, const char **strings); #define PROP_STRING_PARM(var, no) \ const char *var = params[(no)+1].s; +#define PROP_EXP_PARM(var, no) \ + FxExpression *var = params[(no)+1].exp; + #define PROP_INT_PARM(var, no) \ int var = params[(no)+1].i; @@ -375,44 +387,6 @@ int MatchString (const char *in, const char **strings); } -int EvalExpressionI (DWORD x, AActor *self); -int EvalExpressionCol (DWORD x, AActor *self); -FSoundID EvalExpressionSnd (DWORD x, AActor *self); -double EvalExpressionF (DWORD x, AActor *self); -fixed_t EvalExpressionFix (DWORD x, AActor *self); -FState *EvalExpressionState (DWORD x, AActor *self); -const PClass *EvalExpressionClass (DWORD x, AActor *self); -FName EvalExpressionName (DWORD x, AActor *self); - -#if 0 -#define ACTION_PARAM_START(count) - -#define ACTION_PARAM_INT(var, i) \ - int var = EvalExpressionI(ParameterIndex+i, self); -#define ACTION_PARAM_BOOL(var,i) \ - bool var = !!EvalExpressionI(ParameterIndex+i, self); -#define ACTION_PARAM_FIXED(var,i) \ - fixed_t var = EvalExpressionFix(ParameterIndex+i, self); -#define ACTION_PARAM_FLOAT(var,i) \ - float var = float(EvalExpressionF(ParameterIndex+i, self)); -#define ACTION_PARAM_DOUBLE(var,i) \ - double var = EvalExpressionF(ParameterIndex+i, self); -#define ACTION_PARAM_CLASS(var,i) \ - const PClass *var = EvalExpressionClass(ParameterIndex+i, self); -#define ACTION_PARAM_STATE(var,i) \ - FState *var = EvalExpressionState(ParameterIndex+i, stateowner); -#define ACTION_PARAM_COLOR(var,i) \ - PalEntry var = EvalExpressionCol(ParameterIndex+i, self); -#define ACTION_PARAM_SOUND(var,i) \ - FSoundID var = EvalExpressionSnd(ParameterIndex+i, self); -#define ACTION_PARAM_STRING(var,i) \ - const char *var = EvalExpressionName(ParameterIndex+i, self); -#define ACTION_PARAM_NAME(var,i) \ - FName var = EvalExpressionName(ParameterIndex+i, self); -#define ACTION_PARAM_ANGLE(var,i) \ - angle_t var = angle_t(EvalExpressionF(ParameterIndex+i, self)*ANGLE_90/90.f); -#endif - #define ACTION_SET_RESULT(v) do { if (numret > 0) { assert(ret != NULL); ret->SetInt(v); numret = 1; } } while(0) // Checks to see what called the current action function diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index ccf73eb34..abca3c722 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -904,6 +904,28 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// +// +//========================================================================== + +class FxDamageValue : public FxExpression +{ + FxExpression *val; + bool Calculated; + VMScriptFunction *MyFunction; + +public: + + FxDamageValue(FxExpression *v, bool calc); + ~FxDamageValue(); + FxExpression *Resolve(FCompileContext&); + + ExpEmit Emit(VMFunctionBuilder *build); + VMScriptFunction *GetFunction() const { return MyFunction; } + void SetFunction(VMScriptFunction *func) { MyFunction = func; } +}; FxExpression *ParseExpression (FScanner &sc, PClassActor *cls); diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index ea5c5005e..7c68d99b5 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -79,7 +79,7 @@ DEFINE_MEMBER_VARIABLE_ALIAS(momy, vely, AActor) DEFINE_MEMBER_VARIABLE_ALIAS(momz, velz, AActor) DEFINE_MEMBER_VARIABLE(scaleX, AActor) DEFINE_MEMBER_VARIABLE(scaleY, AActor) -DEFINE_MEMBER_VARIABLE(Damage, AActor) +//DEFINE_MEMBER_VARIABLE(Damage, AActor) DEFINE_MEMBER_VARIABLE(Score, AActor) DEFINE_MEMBER_VARIABLE(accuracy, AActor) DEFINE_MEMBER_VARIABLE(stamina, AActor) @@ -120,89 +120,6 @@ static PSymbol *FindDecorateBuiltinFunction(FName funcname, VMNativeFunction::Na return sym; } -//========================================================================== -// -// EvalExpression -// [GRB] Evaluates previously stored expression -// -//========================================================================== - - -int EvalExpressionI (DWORD xi, AActor *self) -{ - FxExpression *x = StateParams.Get(xi); - if (x == NULL) return 0; - - return x->EvalExpression (self).GetInt(); -} - -int EvalExpressionCol (DWORD xi, AActor *self) -{ - FxExpression *x = StateParams.Get(xi); - if (x == NULL) return 0; - - return x->EvalExpression (self).GetColor(); -} - -FSoundID EvalExpressionSnd (DWORD xi, AActor *self) -{ - FxExpression *x = StateParams.Get(xi); - if (x == NULL) return 0; - - return x->EvalExpression (self).GetSoundID(); -} - -double EvalExpressionF (DWORD xi, AActor *self) -{ - FxExpression *x = StateParams.Get(xi); - if (x == NULL) return 0; - - return x->EvalExpression (self).GetFloat(); -} - -fixed_t EvalExpressionFix (DWORD xi, AActor *self) -{ - FxExpression *x = StateParams.Get(xi); - if (x == NULL) return 0; - - ExpVal val = x->EvalExpression (self); - - switch (val.Type) - { - default: - return 0; - case VAL_Int: - return val.Int << FRACBITS; - case VAL_Float: - return fixed_t(val.Float*FRACUNIT); - } -} - -FName EvalExpressionName (DWORD xi, AActor *self) -{ - FxExpression *x = StateParams.Get(xi); - if (x == NULL) return 0; - - return x->EvalExpression (self).GetName(); -} - -const PClass * EvalExpressionClass (DWORD xi, AActor *self) -{ - FxExpression *x = StateParams.Get(xi); - if (x == NULL) return 0; - - return x->EvalExpression (self).GetClass(); -} - -FState *EvalExpressionState (DWORD xi, AActor *self) -{ - FxExpression *x = StateParams.Get(xi); - if (x == NULL) return 0; - - return x->EvalExpression (self).GetState(); -} - - //========================================================================== // // @@ -4025,6 +3942,64 @@ ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build) return dest; } +//========================================================================== +// +// +// +//========================================================================== + +FxDamageValue::FxDamageValue(FxExpression *v, bool calc) +: FxExpression(v->ScriptPosition) +{ + val = v; + ValueType = VAL_Unknown; + Calculated = calc; + MyFunction = NULL; + + if (!calc) + { + assert(v->isConstant() && "Non-calculated damage must be constant"); + } +} + +FxDamageValue::~FxDamageValue() +{ + SAFE_DELETE(val); + +} + +FxExpression *FxDamageValue::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(val, ctx) + + if (!val->ValueType.isNumeric()) + { + ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); + delete this; + return NULL; + } + return this; +} + +// This is a highly-specialized "expression" type that emits a complete function. +ExpEmit FxDamageValue::Emit(VMFunctionBuilder *build) +{ + if (val->isConstant()) + { + build->EmitRetInt(0, false, val->EvalExpression(NULL).Int); + } + else + { + ExpEmit emitval = val->Emit(build); + assert(emitval.RegType == REGT_INT); + build->Emit(OP_RET, 0, REGT_INT | (emitval.Konst ? REGT_KONST : 0), emitval.RegNum); + } + build->Emit(OP_RETI, 1, 0x8000 | (int)Calculated); + + return ExpEmit(); +} + //========================================================================== // @@ -4096,38 +4071,6 @@ int FStateExpressions::Reserve(int num, PClassActor *cls) // //========================================================================== -void FStateExpressions::Set(int num, FxExpression *x, bool cloned) -{ - if (num >= 0 && num < int(Size())) - { - assert(expressions[num].expr == NULL || expressions[num].cloned); - expressions[num].expr = x; - expressions[num].cloned = cloned; - } -} - -//========================================================================== -// -// -// -//========================================================================== - -void FStateExpressions::Copy(int dest, int src, int cnt) -{ - for(int i=0; i<cnt; i++) - { - // For now set only a reference because these expressions may change when being resolved - expressions[dest+i].expr = (FxExpression*)intptr_t(src+i); - expressions[dest+i].cloned = true; - } -} - -//========================================================================== -// -// -// -//========================================================================== - int FStateExpressions::ResolveAll() { int errorcount = 0; diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 8b974ac8d..c9fb01911 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -669,16 +669,26 @@ static bool ParsePropertyParams(FScanner &sc, FPropertyInfo *prop, AActor *defau switch ((*p) & 223) { case 'X': // Expression in parentheses or number. - - if (sc.CheckString ("(")) { - FxExpression *x = ParseExpression(sc, bag.Info); - conv.i = 0x40000000 | StateParams.Add(x, bag.Info, false); + FxExpression *x = NULL; + + if (sc.CheckString ("(")) + { + x = new FxDamageValue(new FxIntCast(ParseExpression(sc, bag.Info)), true); + sc.MustGetStringName(")"); + } + else + { + sc.MustGetNumber(); + if (sc.Number != 0) + { + x = new FxDamageValue(new FxConstant(sc.Number, bag.ScriptPosition), false); + } + } + conv.exp = x; params.Push(conv); - sc.MustGetStringName(")"); - break; } - // fall through + break; case 'I': sc.MustGetNumber(); diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index 576aa72b1..0d115ec5b 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -449,7 +449,7 @@ DEFINE_PROPERTY(painthreshold, I, Actor) //========================================================================== DEFINE_PROPERTY(damage, X, Actor) { - PROP_INT_PARM(id, 0); + PROP_EXP_PARM(id, 0); // Damage can either be a single number, in which case it is subject // to the original damage calculation rules. Or, it can be an expression @@ -457,7 +457,9 @@ DEFINE_PROPERTY(damage, X, Actor) // compatibility reasons, expressions must be enclosed within // parentheses. - defaults->Damage = id; + // Store this expression here for now. It will be converted to a function + // later once all actors have been processed. + defaults->Damage = (VMFunction *)id; } //========================================================================== diff --git a/src/zscript/vmbuilder.cpp b/src/zscript/vmbuilder.cpp index 4cf613d8f..78051d816 100644 --- a/src/zscript/vmbuilder.cpp +++ b/src/zscript/vmbuilder.cpp @@ -490,6 +490,27 @@ size_t VMFunctionBuilder::EmitLoadInt(int regnum, int value) } } +//========================================================================== +// +// VMFunctionBuilder :: EmitRetInt +// +// Returns an integer, using either an immediate value or a constant +// register, as appropriate. +// +//========================================================================== + +size_t VMFunctionBuilder::EmitRetInt(int retnum, bool final, int value) +{ + if (value >= -16384 && value <= 16383) + { + return Emit(OP_RETI, retnum, value | (final << 15)); + } + else + { + return Emit(OP_RETI, retnum, REGT_INT | REGT_KONST | (final ? REGT_FINAL : 0), GetConstantInt(value)); + } +} + //========================================================================== // // VMFunctionBuilder :: Backpatch diff --git a/src/zscript/vmbuilder.h b/src/zscript/vmbuilder.h index 2399411f6..7587d1b20 100644 --- a/src/zscript/vmbuilder.h +++ b/src/zscript/vmbuilder.h @@ -37,6 +37,7 @@ public: size_t Emit(int opcode, int opa, VM_SHALF opbc); size_t Emit(int opcode, int opabc); size_t EmitLoadInt(int regnum, int value); + size_t EmitRetInt(int retnum, bool final, int value); void Backpatch(size_t addr, size_t target); void BackpatchToHere(size_t addr); diff --git a/src/zscript/vmdisasm.cpp b/src/zscript/vmdisasm.cpp index 81eb50bba..77abf9d12 100644 --- a/src/zscript/vmdisasm.cpp +++ b/src/zscript/vmdisasm.cpp @@ -43,6 +43,7 @@ #define RII16 MODE_AI | MODE_BCJOINT | MODE_BCIMMS #define I24 MODE_ABCJOINT #define I8 MODE_AIMMZ | MODE_BUNUSED | MODE_CUNUSED +#define I8I16 MODE_AIMMZ | MODE_BCIMMZ #define __BCP MODE_AUNUSED | MODE_BCJOINT | MODE_BCPARAM #define RPI8 MODE_AP | MODE_BIMMZ | MODE_CUNUSED #define KPI8 MODE_AKP | MODE_BIMMZ | MODE_CUNUSED @@ -246,6 +247,22 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction } break; + case OP_RETI: + if (a == 0 && code[i].i16 & 0x8000) + { + col = printf_wrapper(out, "%d", (code[i].i16 << 17) >> 17); + } + else + { + col = print_reg(out, 0, a, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func); + col += print_reg(out, col, (code[i].i16 << 17) >> 17, MODE_IMMS, 16, func); + if (code[i].i16 & 0x8000) + { + col += printf_wrapper(out, " [final]"); + } + } + break; + default: if ((mode & MODE_BCTYPE) == MODE_BCCAST) { diff --git a/src/zscript/vmexec.h b/src/zscript/vmexec.h index ff9b471d5..a1a22a964 100644 --- a/src/zscript/vmexec.h +++ b/src/zscript/vmexec.h @@ -593,6 +593,18 @@ begin: return a < numret ? a + 1 : numret; } NEXTOP; + OP(RETI): + assert(ret != NULL || numret == 0); + if (a < numret) + { + // Shifting by 17 to wipe out the final bit + ret[a].SetInt(((pc[-1].i16) << 17) >> 17); + } + if (pc[-1].i16 & 0x8000) + { + return a < numret ? a + 1 : numret; + } + NEXTOP; OP(RESULT): // This instruction is just a placeholder to indicate where a return // value should be stored. It does nothing on its own and should not diff --git a/src/zscript/vmops.h b/src/zscript/vmops.h index 78ef5116f..353dc3e85 100644 --- a/src/zscript/vmops.h +++ b/src/zscript/vmops.h @@ -81,6 +81,7 @@ xx(TAIL, tail, RPI8), // Call+Ret in a single instruction xx(TAIL_K, tail, KPI8), xx(RESULT, result, __BCP), // Result should go in register encoded in BC (in caller, after CALL) xx(RET, ret, I8BCP), // Copy value from register encoded in BC to return value A, possibly returning +xx(RETI, reti, I8I16), // Copy immediate from BC to return value A, possibly returning xx(TRY, try, I24), // When an exception is thrown, start searching for a handler at pc + ABC xx(UNTRY, untry, I8), // Pop A entries off the exception stack xx(THROW, throw, THROW), // A == 0: Throw exception object pB diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index a6c7bd1c5..1f50643da 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -41,7 +41,7 @@ ACTOR Actor native //: Thinker native int tid; native int TIDtoHate; native int waterlevel; - native int damage; + //native int damage; native fixed_t x; native fixed_t y; native fixed_t z; From b630410372014ea0fda9f7b44db9d0f8d1fb99d8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers <coelckers@zdoom.fake> Date: Sun, 28 Oct 2012 06:56:56 +0000 Subject: [PATCH 074/232] - fixed: CreateDamageFunction needs to return NULL for a damage value of 0 to preserve the collision detection handling of non-damaging actors. SVN r3920 (scripting) --- src/p_mobj.cpp | 3 ++- src/thingdef/thingdef.cpp | 22 +++++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 458ed36f0..c1be116ee 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3410,7 +3410,8 @@ void AActor::Tick () // won't hurt anything. Don't do this if damage is 0! That way, you can // still have missiles that go straight up and down through actors without // damaging anything. - if ((flags & MF_MISSILE) && (velx|vely) == 0 && Damage != 0) + // (for backwards compatibility this must check for lack of damage function, not for zero damage!) + if ((flags & MF_MISSILE) && (velx|vely) == 0 && Damage != NULL) { velx = 1; } diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index d162a9f10..8a3589a99 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -446,11 +446,19 @@ void LoadActors () VMScriptFunction *CreateDamageFunction(int dmg) { - VMFunctionBuilder build; - build.Registers[REGT_POINTER].Get(1); // The self pointer - build.EmitRetInt(0, false, dmg); - build.EmitRetInt(1, true, 0); - VMScriptFunction *sfunc = build.MakeFunction(); - sfunc->NumArgs = 1; - return sfunc; + if (dmg == 0) + { + // For zero damage, do not create a function so that the special collision detection case still works as before. + return NULL; + } + else + { + VMFunctionBuilder build; + build.Registers[REGT_POINTER].Get(1); // The self pointer + build.EmitRetInt(0, false, dmg); + build.EmitRetInt(1, true, 0); + VMScriptFunction *sfunc = build.MakeFunction(); + sfunc->NumArgs = 1; + return sfunc; + } } From 35ba5b79d3f20560c5e00fe6151de10016f96c53 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Mon, 29 Oct 2012 00:42:58 +0000 Subject: [PATCH 075/232] - Added a NULL Defaults check to PClassActor::PropagateMark(). SVN r3921 (scripting) --- src/info.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/info.cpp b/src/info.cpp index 523855084..244c9c68b 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -303,7 +303,10 @@ size_t PClassActor::PropagateMark() } } // Mark damage function - GC::Mark(((AActor *)Defaults)->Damage); + if (Defaults != NULL) + { + GC::Mark(((AActor *)Defaults)->Damage); + } // marked += ActorInfo->NumOwnedStates * sizeof(FState); return Super::PropagateMark(); From c2e700f11600e5c91b44b6a46d0ef1f1c0b73626 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Mon, 29 Oct 2012 01:11:24 +0000 Subject: [PATCH 076/232] - Move the RET and RETI final flag into the high bit of the destination selector. SVN r3922 (scripting) --- src/thingdef/thingdef_expression.cpp | 2 +- src/zscript/vm.h | 4 +++- src/zscript/vmbuilder.cpp | 7 +++--- src/zscript/vmdisasm.cpp | 16 +++++++------- src/zscript/vmexec.h | 33 ++++++++++++++++------------ 5 files changed, 35 insertions(+), 27 deletions(-) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 7c68d99b5..7aa7b8d34 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3995,7 +3995,7 @@ ExpEmit FxDamageValue::Emit(VMFunctionBuilder *build) assert(emitval.RegType == REGT_INT); build->Emit(OP_RET, 0, REGT_INT | (emitval.Konst ? REGT_KONST : 0), emitval.RegNum); } - build->Emit(OP_RETI, 1, 0x8000 | (int)Calculated); + build->Emit(OP_RETI, 1 | RET_FINAL, Calculated); return ExpEmit(); } diff --git a/src/zscript/vm.h b/src/zscript/vm.h index 256578a8e..2d87b7209 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -119,12 +119,14 @@ enum REGT_KONST = 4, REGT_MULTIREG = 8, // (e.g. a vector) - REGT_FINAL = 16, // used with RET: this is the final return value REGT_ADDROF = 32, // used with PARAM: pass address of this register REGT_NIL = 255 // parameter was omitted }; +#define RET_FINAL (0x80) // Used with RET and RETI in the destination slot: this is the final return value + + // Tags for address registers enum { diff --git a/src/zscript/vmbuilder.cpp b/src/zscript/vmbuilder.cpp index 78051d816..c87ff636a 100644 --- a/src/zscript/vmbuilder.cpp +++ b/src/zscript/vmbuilder.cpp @@ -501,13 +501,14 @@ size_t VMFunctionBuilder::EmitLoadInt(int regnum, int value) size_t VMFunctionBuilder::EmitRetInt(int retnum, bool final, int value) { - if (value >= -16384 && value <= 16383) + assert(retnum >= 0 && retnum <= 127); + if (value >= -32768 && value <= 32767) { - return Emit(OP_RETI, retnum, value | (final << 15)); + return Emit(OP_RETI, retnum | (final << 7), value); } else { - return Emit(OP_RETI, retnum, REGT_INT | REGT_KONST | (final ? REGT_FINAL : 0), GetConstantInt(value)); + return Emit(OP_RET, retnum | (final << 7), REGT_INT | REGT_KONST, GetConstantInt(value)); } } diff --git a/src/zscript/vmdisasm.cpp b/src/zscript/vmdisasm.cpp index 77abf9d12..d2e87956d 100644 --- a/src/zscript/vmdisasm.cpp +++ b/src/zscript/vmdisasm.cpp @@ -231,15 +231,15 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction case OP_RET: if (code[i].b != REGT_NIL) { - if ((code[i].b & REGT_FINAL) && a == 0) + if (a == RET_FINAL) { col = print_reg(out, 0, code[i].i16u, MODE_PARAM, 16, func); } else { - col = print_reg(out, 0, a, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func); + col = print_reg(out, 0, a & ~RET_FINAL, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func); col += print_reg(out, col, code[i].i16u, MODE_PARAM, 16, func); - if (code[i].b & REGT_FINAL) + if (a & RET_FINAL) { col += printf_wrapper(out, " [final]"); } @@ -248,15 +248,15 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction break; case OP_RETI: - if (a == 0 && code[i].i16 & 0x8000) + if (a == RET_FINAL) { - col = printf_wrapper(out, "%d", (code[i].i16 << 17) >> 17); + col = printf_wrapper(out, "%d", code[i].i16); } else { - col = print_reg(out, 0, a, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func); - col += print_reg(out, col, (code[i].i16 << 17) >> 17, MODE_IMMS, 16, func); - if (code[i].i16 & 0x8000) + col = print_reg(out, 0, a & ~RET_FINAL, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func); + col += print_reg(out, col, code[i].i16, MODE_IMMS, 16, func); + if (a & RET_FINAL) { col += printf_wrapper(out, " [final]"); } diff --git a/src/zscript/vmexec.h b/src/zscript/vmexec.h index a1a22a964..e901e5f03 100644 --- a/src/zscript/vmexec.h +++ b/src/zscript/vmexec.h @@ -584,25 +584,30 @@ begin: return 0; } assert(ret != NULL || numret == 0); - if (a < numret) { - SetReturn(reg, f, &ret[a], B, C); - } - if (B & REGT_FINAL) - { - return a < numret ? a + 1 : numret; + int retnum = a & ~RET_FINAL; + if (retnum < numret) + { + SetReturn(reg, f, &ret[retnum], B, C); + } + if (a & RET_FINAL) + { + return retnum < numret ? retnum + 1 : numret; + } } NEXTOP; OP(RETI): assert(ret != NULL || numret == 0); - if (a < numret) { - // Shifting by 17 to wipe out the final bit - ret[a].SetInt(((pc[-1].i16) << 17) >> 17); - } - if (pc[-1].i16 & 0x8000) - { - return a < numret ? a + 1 : numret; + int retnum = a & ~RET_FINAL; + if (retnum < numret) + { + ret[retnum].SetInt(BCs); + } + if (a & RET_FINAL) + { + return retnum < numret ? retnum + 1 : numret; + } } NEXTOP; OP(RESULT): @@ -1490,7 +1495,7 @@ static void SetReturn(const VMRegisters ®, VMFrame *frame, VMReturn *ret, VM_ VMScriptFunction *func = static_cast<VMScriptFunction *>(frame->Func); assert(func != NULL && !func->Native); - assert((regtype & ~(REGT_KONST | REGT_FINAL)) == ret->RegType); + assert((regtype & ~REGT_KONST) == ret->RegType); switch (regtype & REGT_TYPE) { From e7168b3a51ee2119d7168b538973465b6643526b Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Mon, 29 Oct 2012 01:13:26 +0000 Subject: [PATCH 077/232] - Transform the Actor Damage functions to/from an integer for saving. (I am occasionally encountering unknown class "None" when loading now, which is not so nice.) SVN r3923 (scripting) --- src/p_mobj.cpp | 88 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 2 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index c1be116ee..981e6a4b2 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -145,6 +145,79 @@ AActor::~AActor () // Use Destroy() instead. } +//========================================================================== +// +// CalcDamageValue +// +// Given a script function, returns an integer to represent it in a +// savegame. This encoding is compatible with previous incarnations +// where damage was an integer. +// +// 0 : use null function +// 0x40000000 : use default function +// anything else : use function that returns this number +// +//========================================================================== + +static int CalcDamageValue(VMFunction *func) +{ + if (func == NULL) + { + return 0; + } + VMScriptFunction *sfunc = dyn_cast<VMScriptFunction>(func); + if (sfunc == NULL) + { + return 0x40000000; + } + VMOP *op = sfunc->Code; + // If the function was created by CreateDamageFunction(), extract + // the value used to create it and return that. Otherwise, return + // indicating to use the default function. + if (op->op == OP_RETI && op->a == 0) + { + return op->i16; + } + if (op->op == OP_RET && op->a == 0 && op->b == (REGT_INT | REGT_KONST)) + { + return sfunc->KonstD[op->c]; + } + return 0x40000000; +} + +//========================================================================== +// +// UncalcDamageValue +// +// Given a damage integer, returns a script function for it. +// +//========================================================================== + +static VMFunction *UncalcDamageValue(int dmg, VMFunction *def) +{ + if (dmg == 0) + { + return NULL; + } + if ((dmg & 0xC0000000) == 0x40000000) + { + return def; + } + // Does the default version return this? If so, use it. Otherwise, + // create a new function. + if (CalcDamageValue(def) == dmg) + { + return def; + } + return CreateDamageFunction(dmg); +} + +//========================================================================== +// +// AActor :: Serialize +// +//========================================================================== + void AActor::Serialize (FArchive &arc) { Super::Serialize (arc); @@ -191,8 +264,19 @@ void AActor::Serialize (FArchive &arc) << vely << velz << tics - << state - << Damage; + << state; + if (arc.IsStoring()) + { + int dmg; + dmg = CalcDamageValue(Damage); + arc << dmg; + } + else + { + int dmg; + arc << dmg; + Damage = UncalcDamageValue(dmg, GetDefault()->Damage); + } if (SaveVersion >= 3227) { arc << projectileKickback; From 80782d7e5e17d3d9c4ed53d8b3bd1895e21a2ecd Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 30 Oct 2012 01:38:05 +0000 Subject: [PATCH 078/232] - Fixed: Because PClass is a child of DObject now, attempts to serialize them get caught by the DObject serialization template. Therefore, FArchive::SerializeObject() needs to be able to handle them specially from other objects. SVN r3924 (scripting) --- src/farchive.cpp | 38 ++++++++++++++++++++------------------ src/farchive.h | 2 -- src/p_user.cpp | 2 +- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/farchive.cpp b/src/farchive.cpp index 4a1936f38..6759b40de 100644 --- a/src/farchive.cpp +++ b/src/farchive.cpp @@ -1024,13 +1024,28 @@ FArchive &FArchive::SerializePointer (void *ptrbase, BYTE **ptr, DWORD elemSize) FArchive &FArchive::SerializeObject (DObject *&object, PClass *type) { - if (IsStoring ()) - { - return WriteObject (object); + if (!type->IsDescendantOf(RUNTIME_CLASS(PClass))) + { // a regular object + if (IsStoring()) + { + return WriteObject(object); + } + else + { + return ReadObject(object, type); + } } else - { - return ReadObject (object, type); + { // a class object + if (IsStoring()) + { + UserWriteClass((PClass *)object); + } + else + { + UserReadClass(object); + } + return *this; } } @@ -1493,19 +1508,6 @@ void FArchive::UserReadClass (PClass *&type) } } -FArchive &operator<< (FArchive &arc, PClass *&info) -{ - if (arc.IsStoring ()) - { - arc.UserWriteClass (info); - } - else - { - arc.UserReadClass (info); - } - return arc; -} - FArchive &operator<< (FArchive &arc, sector_t *&sec) { return arc.SerializePointer (sectors, (BYTE **)&sec, sizeof(*sectors)); diff --git a/src/farchive.h b/src/farchive.h index 1a6f98ec5..7b9327d59 100644 --- a/src/farchive.h +++ b/src/farchive.h @@ -275,8 +275,6 @@ inline FArchive &operator<< (FArchive &arc, T* &object) return arc.SerializeObject ((DObject*&)object, RUNTIME_TEMPLATE_CLASS(T)); } -FArchive &operator<< (FArchive &arc, PClass * &info); - class FFont; FArchive &SerializeFFontPtr (FArchive &arc, FFont* &font); template<> inline FArchive &operator<< <FFont> (FArchive &arc, FFont* &font) diff --git a/src/p_user.cpp b/src/p_user.cpp index c86cf186d..27ecfe60e 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -137,7 +137,7 @@ void SetupPlayerClasses () PlayerClasses.Clear(); for (unsigned i = 0; i < gameinfo.PlayerClasses.Size(); i++) { - PClassActor *cls = PClass::FindActor(gameinfo.PlayerClasses[i]);; + PClassActor *cls = PClass::FindActor(gameinfo.PlayerClasses[i]); if (ValidatePlayerClass(cls, gameinfo.PlayerClasses[i])) { newclass.Flags = 0; From d50a16a847e8bb3779a16f1bc5cc2dc6cf19b541 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 30 Oct 2012 02:09:57 +0000 Subject: [PATCH 079/232] - Fixed: The AmmoPerAttack table was filled with the function pointers before the functions were created, so they were all NULL, and the Dehacked ammo modification loop failed to find any of them in the weapon. The result being that all standard weapons were left with an AmmoUse1 of 0. SVN r3925 (scripting) --- src/d_dehacked.cpp | 45 +++++++++++++-------------------------------- 1 file changed, 13 insertions(+), 32 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index c1e3b2800..8531f1fea 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -164,7 +164,7 @@ static TArray<CodePointerAlias> MBFCodePointers; struct AmmoPerAttack { - VMFunction *func; + VMNativeFunction **func; int ammocount; }; @@ -182,17 +182,17 @@ DECLARE_ACTION(A_FireRailgun) // Default ammo use of the various weapon attacks static AmmoPerAttack AmmoPerAttacks[] = { - { A_Punch_VMPtr, 0}, - { A_FirePistol_VMPtr, 1}, - { A_FireShotgun_VMPtr, 1}, - { A_FireShotgun2_VMPtr, 2}, - { A_FireCGun_VMPtr, 1}, - { A_FireMissile_VMPtr, 1}, - { A_Saw_VMPtr, 0}, - { A_FirePlasma_VMPtr, 1}, - { A_FireBFG_VMPtr, -1}, // uses deh.BFGCells - { A_FireOldBFG_VMPtr, 1}, - { A_FireRailgun_VMPtr, 1}, + { &A_Punch_VMPtr, 0}, + { &A_FirePistol_VMPtr, 1}, + { &A_FireShotgun_VMPtr, 1}, + { &A_FireShotgun2_VMPtr, 2}, + { &A_FireCGun_VMPtr, 1}, + { &A_FireMissile_VMPtr, 1}, + { &A_Saw_VMPtr, 0}, + { &A_FirePlasma_VMPtr, 1}, + { &A_FireBFG_VMPtr, -1}, // uses deh.BFGCells + { &A_FireOldBFG_VMPtr, 1}, + { &A_FireRailgun_VMPtr, 1}, { NULL, 0} }; @@ -2481,25 +2481,6 @@ static inline bool CompareLabel (const char *want, const BYTE *have) return *(DWORD *)want == *(DWORD *)have; } -static inline short GetWord (const BYTE *in) -{ - return (in[0] << 8) | (in[1]); -} - -static short *GetWordSpace (void *in, size_t size) -{ - short *ptr; - size_t i; - - ptr = (short *)in; - - for (i = 0; i < size; i++) - { - ptr[i] = GetWord ((BYTE *)in + i*2); - } - return ptr; -} - static int DehUseCount; static void UnloadDehSupp () @@ -2969,7 +2950,7 @@ void FinishDehPatch () StateVisited[state] = true; for(unsigned j = 0; AmmoPerAttacks[j].func != NULL; j++) { - if (state->ActionFunc == AmmoPerAttacks[j].func) + if (state->ActionFunc == *AmmoPerAttacks[j].func) { found = true; int use = AmmoPerAttacks[j].ammocount; From 78196063dad273be818043cd6e6a53838e24be2c Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 25 Jun 2013 19:29:49 -0500 Subject: [PATCH 080/232] - Add generated zcc-parse files to .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 09e3fb4c4..9e31a3bbc 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,9 @@ /src/xlat/xlat_parser.c /src/xlat/xlat_parser.h /src/xlat/xlat_parser.out +/src/zscript/zcc-parse.c +/src/zscript/zcc-parse.h +/src/zscript/zcc-parse.out /tools/*/debug /tools/*/release /tools/*/*.exe From 572823046c4de04fad313b0b2238a0370feeb743 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 10 Jul 2013 23:26:01 -0500 Subject: [PATCH 081/232] Add newlines for better readability in AST dump. --- src/zscript/ast.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/zscript/ast.cpp b/src/zscript/ast.cpp index d4a98691e..f3a809b0e 100644 --- a/src/zscript/ast.cpp +++ b/src/zscript/ast.cpp @@ -115,7 +115,7 @@ static void PrintStringConst(FString &out, FString str) static void PrintClass(FString &out, ZCC_TreeNode *node) { ZCC_Class *cnode = (ZCC_Class *)node; - out << "(class "; + out << "\n(class "; PrintNodes(out, cnode->ClassName); PrintNodes(out, cnode->ParentName); PrintNodes(out, cnode->Replaces); @@ -126,14 +126,14 @@ static void PrintClass(FString &out, ZCC_TreeNode *node) static void PrintStruct(FString &out, ZCC_TreeNode *node) { ZCC_Struct *snode = (ZCC_Struct *)node; - out.AppendFormat("(struct '%s' ", FName(snode->StructName).GetChars()); + out.AppendFormat("\n(struct '%s' ", FName(snode->StructName).GetChars()); PrintNodes(out, snode->Body, ')'); } static void PrintEnum(FString &out, ZCC_TreeNode *node) { ZCC_Enum *enode = (ZCC_Enum *)node; - out.AppendFormat("(enum '%s' ", FName(enode->EnumName).GetChars()); + out.AppendFormat("\n(enum '%s' ", FName(enode->EnumName).GetChars()); PrintBuiltInType(out, enode->EnumType, true); PrintNodes(out, enode->Elements, ')'); } @@ -148,7 +148,7 @@ static void PrintEnumNode(FString &out, ZCC_TreeNode *node) static void PrintStates(FString &out, ZCC_TreeNode *node) { ZCC_States *snode = (ZCC_States *)node; - out << "(states "; + out << "\n(states "; PrintNodes(out, snode->Body, ')'); } @@ -160,7 +160,7 @@ static void PrintStatePart(FString &out, ZCC_TreeNode *node) static void PrintStateLabel(FString &out, ZCC_TreeNode *node) { ZCC_StateLabel *snode = (ZCC_StateLabel *)node; - out.AppendFormat("(state-label '%s')", FName(snode->Label).GetChars()); + out.AppendFormat("\n(state-label '%s')", FName(snode->Label).GetChars()); } static void PrintStateStop(FString &out, ZCC_TreeNode *node) @@ -194,7 +194,7 @@ static void PrintStateGoto(FString &out, ZCC_TreeNode *node) static void PrintStateLine(FString &out, ZCC_TreeNode *node) { ZCC_StateLine *snode = (ZCC_StateLine *)node; - out.AppendFormat("(state-line %c%c%c%c %s %s ", + out.AppendFormat("\n(state-line %c%c%c%c %s %s ", snode->Sprite[0], snode->Sprite[1], snode->Sprite[2], snode->Sprite[3], snode->bBright ? "bright " : "", snode->Frames->GetChars()); @@ -535,19 +535,21 @@ static void PrintDeclarator(FString &out, ZCC_TreeNode *node) static void PrintVarDeclarator(FString &out, ZCC_TreeNode *node) { ZCC_VarDeclarator *dnode = (ZCC_VarDeclarator *)node; - out << "(var-declarator "; + out << "\n(var-declarator "; PrintNodes(out, dnode->Type); out.AppendFormat("%x ", dnode->Flags); PrintNodes(out, dnode->Names, ')'); + out << '\n'; } static void PrintFuncDeclarator(FString &out, ZCC_TreeNode *node) { ZCC_FuncDeclarator *dnode = (ZCC_FuncDeclarator *)node; - out << "(func-declarator "; + out << "\n(func-declarator "; PrintNodes(out, dnode->Type); out.AppendFormat("%x %s ", dnode->Flags, FName(dnode->Name).GetChars()); PrintNodes(out, dnode->Params, ')'); + out << '\n'; } void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FString &, ZCC_TreeNode *) = From 6088acd4c04b046a8f7055927d4d23d7cca2ac43 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 10 Jul 2013 23:26:56 -0500 Subject: [PATCH 082/232] Add function body to ZCC_FuncDeclarator --- src/zscript/ast.cpp | 3 ++- src/zscript/zcc-parse.lemon | 1 + src/zscript/zcc_parser.h | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/zscript/ast.cpp b/src/zscript/ast.cpp index f3a809b0e..af8ddef68 100644 --- a/src/zscript/ast.cpp +++ b/src/zscript/ast.cpp @@ -548,7 +548,8 @@ static void PrintFuncDeclarator(FString &out, ZCC_TreeNode *node) out << "\n(func-declarator "; PrintNodes(out, dnode->Type); out.AppendFormat("%x %s ", dnode->Flags, FName(dnode->Name).GetChars()); - PrintNodes(out, dnode->Params, ')'); + PrintNodes(out, dnode->Params, ' '); + PrintNodes(out, dnode->Body, ')'); out << '\n'; } diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index ba2776d4b..2cf27336f 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -533,6 +533,7 @@ declarator(X) ::= decl_flags(A) type_list_or_void(B) variables_or_function(C). decl->Params = C.FuncParams; decl->Name = C.FuncName; decl->Flags = A | C.FuncFlags; + decl->Body = C.FuncBody; X = decl; } else if (B != NULL && B->SiblingNext == B) diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index d0d4e3b63..eaaba6192 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -493,6 +493,7 @@ struct ZCC_FuncDeclarator : ZCC_Declarator { ZCC_FuncParamDecl *Params; ENamedName Name; + ZCC_Statement *Body; }; FString ZCC_PrintAST(ZCC_TreeNode *root); From 62fb43d67abe12d4e6a32ad6b875b5ae40770327 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 13 Jul 2013 22:26:29 -0500 Subject: [PATCH 083/232] Properly pass statements around in the parser. --- src/zscript/zcc-parse.lemon | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index 2cf27336f..f9332b629 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -1061,19 +1061,19 @@ constant(X) ::= FLOATCONST(A). /************ Statements ************/ -function_body ::= compound_statement. +function_body(X) ::= compound_statement(A). { X = A; } %type statement{ZCC_Statement *} -statement ::= SEMICOLON. -statement ::= labeled_statement. -statement ::= compound_statement. -statement ::= expression_statement SEMICOLON. -statement ::= selection_statement. -statement ::= iteration_statement. -statement ::= jump_statement. -statement ::= assign_statement SEMICOLON. -statement ::= local_var SEMICOLON. -statement ::= error SEMICOLON. +statement(X) ::= SEMICOLON. { X = NULL; } +statement(X) ::= labeled_statement(A). { X = A; } +statement(X) ::= compound_statement(A). { X = A; } +statement(X) ::= expression_statement(A) SEMICOLON. { X = A; } +statement(X) ::= selection_statement(A). { X = A; } +statement(X) ::= iteration_statement(A). { X = A; } +statement(X) ::= jump_statement(A). { X = A; } +statement(X) ::= assign_statement(A) SEMICOLON. { X = A; } +statement(X) ::= local_var(A) SEMICOLON. { X = A; } +statement(X) ::= error SEMICOLON. { X = NULL; } /*----- Jump Statements -----*/ @@ -1132,8 +1132,8 @@ statement_list(X) ::= statement(A). } statement_list(X) ::= statement_list(A) statement(B). { + SAFE_APPEND(A,B); X = A; - A->AppendSibling(B); } /*----- Expression Statements -----*/ From ec32248f31867762621a4bbdb7fcd8001c26ab36 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 13 Jul 2013 22:34:33 -0500 Subject: [PATCH 084/232] Set value of assign_op explicitly. --- src/zscript/zcc-parse.lemon | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index f9332b629..8081f310b 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -1283,27 +1283,28 @@ labeled_statement(X) ::= DEFAULT COLON. /*----- Assignment Statements -----*/ %type assign_statement{ZCC_AssignStmt *} +%type assign_op{int} assign_statement(X) ::= expr_list(A) assign_op(OP) expr_list(B). [EQ] { NEW_AST_NODE(AssignStmt,stmt); - stmt->AssignOp = OP.Int; + stmt->AssignOp = OP; stmt->Dests = A; stmt->Sources = B; X = stmt; } -assign_op ::= EQ. -assign_op ::= MULEQ. -assign_op ::= DIVEQ. -assign_op ::= MODEQ. -assign_op ::= ADDEQ. -assign_op ::= SUBEQ. -assign_op ::= LSHEQ. -assign_op ::= RSHEQ. -assign_op ::= ANDEQ. -assign_op ::= OREQ. -assign_op ::= XOREQ. +assign_op(X) ::= EQ. { X = ZCC_EQ; } +assign_op(X) ::= MULEQ. { X = ZCC_MULEQ; } +assign_op(X) ::= DIVEQ. { X = ZCC_DIVEQ; } +assign_op(X) ::= MODEQ. { X = ZCC_MODEQ; } +assign_op(X) ::= ADDEQ. { X = ZCC_ADDEQ; } +assign_op(X) ::= SUBEQ. { X = ZCC_SUBEQ; } +assign_op(X) ::= LSHEQ. { X = ZCC_LSHEQ; } +assign_op(X) ::= RSHEQ. { X = ZCC_RSHEQ; } +assign_op(X) ::= ANDEQ. { X = ZCC_ANDEQ; } +assign_op(X) ::= OREQ. { X = ZCC_OREQ; } +assign_op(X) ::= XOREQ. { X = ZCC_XOREQ; } /*----- Local Variable Definition "Statements" -----*/ From a7bbe299e32880aa0ba55054f7bf57767577907a Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 13 Jul 2013 23:25:53 -0500 Subject: [PATCH 085/232] Assignment for expr ::= unary_expr was backwards --- src/zscript/zcc-parse.lemon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index 8081f310b..6c461cc50 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -820,7 +820,7 @@ unary_expr(X) ::= ALIGNOF unary_expr(A). [UNARY] expr(X) ::= unary_expr(A). { - A = X; + X = A; } expr(X) ::= expr(A) ADD expr(B). /* a + b */ { From 726ecaf01baea057637689ef106bcce5a18c6af0 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 17 Jul 2013 23:14:06 -0500 Subject: [PATCH 086/232] Added basic pretty printing for AST dumps --- src/zscript/ast.cpp | 673 ++++++++++++++++++++++++++++---------------- 1 file changed, 430 insertions(+), 243 deletions(-) diff --git a/src/zscript/ast.cpp b/src/zscript/ast.cpp index af8ddef68..42917eb07 100644 --- a/src/zscript/ast.cpp +++ b/src/zscript/ast.cpp @@ -4,7 +4,8 @@ #include "zcc_parser.h" #include "zcc-parse.h" -extern void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FString &, ZCC_TreeNode *); +class FLispString; +extern void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode *); static const char *BuiltInTypeNames[] = { @@ -23,7 +24,129 @@ static const char *BuiltInTypeNames[] = "usertype" }; -static void PrintNode(FString &out, ZCC_TreeNode *node) +class FLispString +{ +public: + operator FString &() { return Str; } + + FLispString() + { + NestDepth = Column = 0; + WrapWidth = 72; + NeedSpace = false; + } + + void Open(const char *label) + { + size_t labellen = label != NULL ? strlen(label) : 0; + CheckWrap(labellen + 1 + NeedSpace); + if (NeedSpace) + { + Str << ' '; + } + Str << '('; + if (label != NULL) + { + Str.AppendCStrPart(label, labellen); + } + Column += labellen + 1 + NeedSpace; + NestDepth++; + NeedSpace = (label != NULL); + } + void Close() + { + assert(NestDepth != 0); + Str << ')'; + Column++; + NestDepth--; + NeedSpace = true; + } + void Break() + { + // Don't break if not needed. + if (Column != NestDepth) + { + Str << '\n'; + Column = NestDepth; + NeedSpace = false; + if (NestDepth > 0) + { + Str.AppendFormat("%*s", NestDepth, ""); + } + } + } + bool CheckWrap(size_t len) + { + if (len + Column > WrapWidth) + { + Break(); + return true; + } + return false; + } + void Add(const char *str, size_t len) + { + CheckWrap(len + NeedSpace); + if (NeedSpace) + { + Str << ' '; + } + Str.AppendCStrPart(str, len); + Column += len + NeedSpace; + NeedSpace = true; + } + void Add(const char *str) + { + Add(str, strlen(str)); + } + void Add(FString &str) + { + Add(str.GetChars(), str.Len()); + } + void AddName(FName name) + { + size_t namelen = strlen(name.GetChars()); + CheckWrap(namelen + 2 + NeedSpace); + if (NeedSpace) + { + NeedSpace = false; + Str << ' '; + } + Str << '\'' << name.GetChars() << '\''; + Column += namelen + 2 + NeedSpace; + NeedSpace = true; + } + void AddChar(char c) + { + Add(&c, 1); + } + void AddInt(int i) + { + char buf[16]; + size_t len = mysnprintf(buf, countof(buf), "%d", i); + Add(buf, len); + } + void AddHex(unsigned x) + { + char buf[10]; + size_t len = mysnprintf(buf, countof(buf), "%08x", x); + Add(buf, len); + } + void AddFloat(double f) + { + char buf[32]; + size_t len = mysnprintf(buf, countof(buf), "%g", f); + Add(buf, len); + } +private: + FString Str; + size_t NestDepth; + size_t Column; + size_t WrapWidth; + bool NeedSpace; +}; + +static void PrintNode(FLispString &out, ZCC_TreeNode *node) { assert(TreeNodePrinter[NUM_AST_NODE_TYPES-1] != NULL); if (node->NodeType >= 0 && node->NodeType < NUM_AST_NODE_TYPES) @@ -32,528 +155,592 @@ static void PrintNode(FString &out, ZCC_TreeNode *node) } else { - out.AppendFormat("(unknown-node-type-%d)", node->NodeType); + out.Open("unknown-node-type"); + out.AddInt(node->NodeType); + out.Close(); } } -static void PrintNodes(FString &out, ZCC_TreeNode *node, char addchar=' ') +static void PrintNodes(FLispString &out, ZCC_TreeNode *node) { ZCC_TreeNode *p; if (node == NULL) { - out << "nil"; + out.Add("nil", 3); } else { - out << '('; + out.Open(NULL); p = node; do { PrintNode(out, p); p = p->SiblingNext; - if (p != node) - { - out << ' '; - } } while (p != node); - out << ')'; - } - if (addchar != '\0') - { - out << addchar; + out.Close(); } } -static void PrintBuiltInType(FString &out, EZCCBuiltinType type, bool addspace) +static void PrintBuiltInType(FLispString &out, EZCCBuiltinType type) { assert(ZCC_NUM_BUILT_IN_TYPES == countof(BuiltInTypeNames)); if (unsigned(type) >= unsigned(ZCC_NUM_BUILT_IN_TYPES)) { - out.AppendFormat("bad-type-%u", type); + char buf[30]; + size_t len = mysnprintf(buf, countof(buf), "bad-type-%u", type); + out.Add(buf, len); } else { - out << BuiltInTypeNames[type]; - } - if (addspace) - { - out << ' '; + out.Add(BuiltInTypeNames[type]); } } -static void PrintIdentifier(FString &out, ZCC_TreeNode *node) +static void PrintIdentifier(FLispString &out, ZCC_TreeNode *node) { ZCC_Identifier *inode = (ZCC_Identifier *)node; - out.AppendFormat("(identifier '%s')", FName(inode->Id).GetChars()); + out.Open("identifier"); + out.AddName(inode->Id); + out.Close(); } -static void PrintStringConst(FString &out, FString str) +static void PrintStringConst(FLispString &out, FString str) { - out << '"'; + FString outstr; + outstr << '"'; for (size_t i = 0; i < str.Len(); ++i) { if (str[i] == '"') { - out << "\""; + outstr << "\""; } else if (str[i] == '\\') { - out << "\\\\"; + outstr << "\\\\"; } else if (str[i] >= 32) { - out << str[i]; + outstr << str[i]; } else { - out.AppendFormat("\\x%02X", str[i]); + outstr.AppendFormat("\\x%02X", str[i]); } } + out.Add(outstr); } -static void PrintClass(FString &out, ZCC_TreeNode *node) +static void PrintClass(FLispString &out, ZCC_TreeNode *node) { ZCC_Class *cnode = (ZCC_Class *)node; - out << "\n(class "; + out.Open("class"); PrintNodes(out, cnode->ClassName); PrintNodes(out, cnode->ParentName); PrintNodes(out, cnode->Replaces); - out.AppendFormat("%08x ", cnode->Flags); - PrintNodes(out, cnode->Body, ')'); + out.AddHex(cnode->Flags); + PrintNodes(out, cnode->Body); + out.Close(); } -static void PrintStruct(FString &out, ZCC_TreeNode *node) +static void PrintStruct(FLispString &out, ZCC_TreeNode *node) { ZCC_Struct *snode = (ZCC_Struct *)node; - out.AppendFormat("\n(struct '%s' ", FName(snode->StructName).GetChars()); - PrintNodes(out, snode->Body, ')'); + out.Break(); + out.Open("struct"); + out.AddName(snode->StructName); + PrintNodes(out, snode->Body); + out.Close(); } -static void PrintEnum(FString &out, ZCC_TreeNode *node) +static void PrintEnum(FLispString &out, ZCC_TreeNode *node) { ZCC_Enum *enode = (ZCC_Enum *)node; - out.AppendFormat("\n(enum '%s' ", FName(enode->EnumName).GetChars()); - PrintBuiltInType(out, enode->EnumType, true); - PrintNodes(out, enode->Elements, ')'); + out.Break(); + out.Open("enum"); + out.AddName(enode->EnumName); + PrintBuiltInType(out, enode->EnumType); + PrintNodes(out, enode->Elements); + out.Close(); } -static void PrintEnumNode(FString &out, ZCC_TreeNode *node) +static void PrintEnumNode(FLispString &out, ZCC_TreeNode *node) { ZCC_EnumNode *enode = (ZCC_EnumNode *)node; - out.AppendFormat("(enum-node '%s' ", FName(enode->ElemName).GetChars()); - PrintNodes(out, enode->ElemValue, ')'); + out.Open("enum-node"); + out.AddName(enode->ElemName); + PrintNodes(out, enode->ElemValue); + out.Close(); } -static void PrintStates(FString &out, ZCC_TreeNode *node) +static void PrintStates(FLispString &out, ZCC_TreeNode *node) { ZCC_States *snode = (ZCC_States *)node; - out << "\n(states "; - PrintNodes(out, snode->Body, ')'); + out.Break(); + out.Open("states"); + PrintNodes(out, snode->Body); + out.Close(); } -static void PrintStatePart(FString &out, ZCC_TreeNode *node) +static void PrintStatePart(FLispString &out, ZCC_TreeNode *node) { - out << "(state-part)"; + out.Open("state-part"); + out.Close(); } -static void PrintStateLabel(FString &out, ZCC_TreeNode *node) +static void PrintStateLabel(FLispString &out, ZCC_TreeNode *node) { ZCC_StateLabel *snode = (ZCC_StateLabel *)node; - out.AppendFormat("\n(state-label '%s')", FName(snode->Label).GetChars()); + out.Break(); + out.Open("state-label"); + out.AddName(snode->Label); + out.Close(); } -static void PrintStateStop(FString &out, ZCC_TreeNode *node) +static void PrintStateStop(FLispString &out, ZCC_TreeNode *node) { - out << "(state-stop)"; + out.Open("state-stop"); + out.Close(); } -static void PrintStateWait(FString &out, ZCC_TreeNode *node) +static void PrintStateWait(FLispString &out, ZCC_TreeNode *node) { - out << "(state-wait)"; + out.Open("state-wait"); + out.Close(); } -static void PrintStateFail(FString &out, ZCC_TreeNode *node) +static void PrintStateFail(FLispString &out, ZCC_TreeNode *node) { - out << "(state-fail)"; + out.Open("state-fail"); + out.Close(); } -static void PrintStateLoop(FString &out, ZCC_TreeNode *node) +static void PrintStateLoop(FLispString &out, ZCC_TreeNode *node) { - out << "(state-loop)"; + out.Open("state-loop"); + out.Close(); } -static void PrintStateGoto(FString &out, ZCC_TreeNode *node) +static void PrintStateGoto(FLispString &out, ZCC_TreeNode *node) { ZCC_StateGoto *snode = (ZCC_StateGoto *)node; - out << "(state-goto "; + out.Open("state-goto"); PrintNodes(out, snode->Label); - PrintNodes(out, snode->Offset, ')'); + PrintNodes(out, snode->Offset); + out.Close(); } -static void PrintStateLine(FString &out, ZCC_TreeNode *node) +static void PrintStateLine(FLispString &out, ZCC_TreeNode *node) { ZCC_StateLine *snode = (ZCC_StateLine *)node; - out.AppendFormat("\n(state-line %c%c%c%c %s %s ", - snode->Sprite[0], snode->Sprite[1], snode->Sprite[2], snode->Sprite[3], - snode->bBright ? "bright " : "", - snode->Frames->GetChars()); + out.Break(); + out.Open("state-line"); + out.Add(snode->Sprite, 4); + if (snode->bBright) + { + out.Add("bright", 6); + } + out.Add(*(snode->Frames)); PrintNodes(out, snode->Offset); - PrintNodes(out, snode->Action, ')'); + PrintNodes(out, snode->Action); + out.Close(); } -static void PrintVarName(FString &out, ZCC_TreeNode *node) +static void PrintVarName(FLispString &out, ZCC_TreeNode *node) { ZCC_VarName *vnode = (ZCC_VarName *)node; - out.AppendFormat("(var-name '%s')", FName(vnode->Name).GetChars()); + out.Open("var-name"); + out.AddName(vnode->Name); + out.Close(); } -static void PrintType(FString &out, ZCC_TreeNode *node) +static void PrintType(FLispString &out, ZCC_TreeNode *node) { ZCC_Type *tnode = (ZCC_Type *)node; - out << "(bad-type "; - PrintNodes(out, tnode->ArraySize, ')'); + out.Open("bad-type"); + PrintNodes(out, tnode->ArraySize); + out.Close(); } -static void PrintBasicType(FString &out, ZCC_TreeNode *node) +static void PrintBasicType(FLispString &out, ZCC_TreeNode *node) { ZCC_BasicType *tnode = (ZCC_BasicType *)node; - out << "(basic-type "; + out.Open("basic-type"); PrintNodes(out, tnode->ArraySize); - PrintBuiltInType(out, tnode->Type, true); - PrintNodes(out, tnode->UserType, ')'); + PrintBuiltInType(out, tnode->Type); + PrintNodes(out, tnode->UserType); + out.Close(); } -static void PrintMapType(FString &out, ZCC_TreeNode *node) +static void PrintMapType(FLispString &out, ZCC_TreeNode *node) { ZCC_MapType *tnode = (ZCC_MapType *)node; - out << "(map-type "; + out.Open("map-type"); PrintNodes(out, tnode->ArraySize); PrintNodes(out, tnode->KeyType); - PrintNodes(out, tnode->ValueType, ')'); + PrintNodes(out, tnode->ValueType); + out.Close(); } -static void PrintDynArrayType(FString &out, ZCC_TreeNode *node) +static void PrintDynArrayType(FLispString &out, ZCC_TreeNode *node) { ZCC_DynArrayType *tnode = (ZCC_DynArrayType *)node; - out << "(dyn-array-type "; + out.Open("dyn-array-type"); PrintNodes(out, tnode->ArraySize); - PrintNodes(out, tnode->ElementType, ')'); + PrintNodes(out, tnode->ElementType); + out.Close(); } -static void PrintClassType(FString &out, ZCC_TreeNode *node) +static void PrintClassType(FLispString &out, ZCC_TreeNode *node) { ZCC_ClassType *tnode = (ZCC_ClassType *)node; - out << "(class-type "; + out.Open("class-type"); PrintNodes(out, tnode->ArraySize); - PrintNodes(out, tnode->Restriction, ')'); + PrintNodes(out, tnode->Restriction); + out.Close(); } -static void PrintExprType(FString &out, EZCCExprType type) +static void OpenExprType(FLispString &out, EZCCExprType type) { static const char *const types[] = { - "nil ", - "id ", - "super ", - "self ", - "string-const ", - "int-const ", - "uint-const ", - "float-const ", - "func-call ", - "array-access ", - "member-access ", - "post-inc ", - "post-dec ", - "pre-inc ", - "pre-dec ", - "negate ", - "anti-negate ", - "bit-not ", - "bool-not ", - "size-of ", - "align-of ", - "add ", - "sub ", - "mul ", - "div ", - "mod ", - "pow ", - "cross-product ", - "dot-product ", - "left-shift ", - "right-shift ", - "concat ", - "lt ", - "gt ", - "lteq ", - "gteq ", - "ltgteq ", - "is ", - "eqeq ", - "neq ", - "apreq ", - "bit-and ", - "bit-or ", - "bit-xor ", - "bool-and ", - "bool-or ", - "scope ", - "trinary ", + "nil", + "id", + "super", + "self", + "string-const", + "int-const", + "uint-const", + "float-const", + "func-call", + "array-access", + "member-access", + "post-inc", + "post-dec", + "pre-inc", + "pre-dec", + "negate", + "anti-negate", + "bit-not", + "bool-not", + "size-of", + "align-of", + "add", + "sub", + "mul", + "div", + "mod", + "pow", + "cross-product", + "dot-product", + "left-shift", + "right-shift", + "concat", + "lt", + "gt", + "lteq", + "gteq", + "ltgteq", + "is", + "eqeq", + "neq", + "apreq", + "bit-and", + "bit-or", + "bit-xor", + "bool-and", + "bool-or", + "scope", + "trinary", }; assert(countof(types) == PEX_COUNT_OF); + char buf[32]; + if (unsigned(type) < countof(types)) { - out << types[type]; + mysnprintf(buf, countof(buf), "expr-%s", types[type]); } else { - out.AppendFormat("bad-pex-%u ", type); + mysnprintf(buf, countof(buf), "bad-pex-%u", type); } + out.Open(buf); } -static void PrintExpression(FString &out, ZCC_TreeNode *node) +static void PrintExpression(FLispString &out, ZCC_TreeNode *node) { ZCC_Expression *enode = (ZCC_Expression *)node; - out << "(expr-"; - PrintExprType(out, enode->Operation); - out << ')'; + OpenExprType(out, enode->Operation); + out.Close(); } -static void PrintExprID(FString &out, ZCC_TreeNode *node) +static void PrintExprID(FLispString &out, ZCC_TreeNode *node) { ZCC_ExprID *enode = (ZCC_ExprID *)node; assert(enode->Operation == PEX_ID); - out.AppendFormat("(expr-id '%s')", FName(enode->Identifier).GetChars()); + out.Open("expr-id"); + out.AddName(enode->Identifier); + out.Close(); } -static void PrintExprString(FString &out, ZCC_TreeNode *node) +static void PrintExprString(FLispString &out, ZCC_TreeNode *node) { ZCC_ExprString *enode = (ZCC_ExprString *)node; assert(enode->Operation == PEX_StringConst); - out.AppendFormat("(expr-string-const "); + out.Open("expr-string-const"); PrintStringConst(out, *enode->Value); - out << ')'; + out.Close(); } -static void PrintExprInt(FString &out, ZCC_TreeNode *node) +static void PrintExprInt(FLispString &out, ZCC_TreeNode *node) { ZCC_ExprInt *enode = (ZCC_ExprInt *)node; assert(enode->Operation == PEX_IntConst || enode->Operation == PEX_UIntConst); - out << "(expr-"; - PrintExprType(out, enode->Operation); - out.AppendFormat("%d)", enode->Value); + OpenExprType(out, enode->Operation); + out.AddInt(enode->Value); + out.Close(); } -static void PrintExprFloat(FString &out, ZCC_TreeNode *node) +static void PrintExprFloat(FLispString &out, ZCC_TreeNode *node) { ZCC_ExprFloat *enode = (ZCC_ExprFloat *)node; assert(enode->Operation == PEX_FloatConst); - out.AppendFormat("(expr-float-const %g)", enode->Value); + out.Open("expr-float-const"); + out.AddFloat(enode->Value); + out.Close(); } -static void PrintExprFuncCall(FString &out, ZCC_TreeNode *node) +static void PrintExprFuncCall(FLispString &out, ZCC_TreeNode *node) { ZCC_ExprFuncCall *enode = (ZCC_ExprFuncCall *)node; assert(enode->Operation == PEX_FuncCall); - out << "(expr-func-call "; + out.Open("expr-func-call"); PrintNodes(out, enode->Function); - PrintNodes(out, enode->Parameters, ')'); + PrintNodes(out, enode->Parameters); + out.Close(); } -static void PrintExprMemberAccess(FString &out, ZCC_TreeNode *node) +static void PrintExprMemberAccess(FLispString &out, ZCC_TreeNode *node) { ZCC_ExprMemberAccess *enode = (ZCC_ExprMemberAccess *)node; assert(enode->Operation == PEX_MemberAccess); - out << "(expr-member-access "; + out.Open("expr-member-access"); PrintNodes(out, enode->Left); - out.AppendFormat("'%s')", FName(enode->Right).GetChars()); + out.AddName(enode->Right); + out.Close(); } -static void PrintExprUnary(FString &out, ZCC_TreeNode *node) +static void PrintExprUnary(FLispString &out, ZCC_TreeNode *node) { ZCC_ExprUnary *enode = (ZCC_ExprUnary *)node; - out << "(expr-"; - PrintExprType(out, enode->Operation); - PrintNodes(out, enode->Operand, ')'); + OpenExprType(out, enode->Operation); + PrintNodes(out, enode->Operand); + out.Close(); } -static void PrintExprBinary(FString &out, ZCC_TreeNode *node) +static void PrintExprBinary(FLispString &out, ZCC_TreeNode *node) { ZCC_ExprBinary *enode = (ZCC_ExprBinary *)node; - out << "(expr-"; - PrintExprType(out, enode->Operation); + OpenExprType(out, enode->Operation); PrintNodes(out, enode->Left); - PrintNodes(out, enode->Right, ')'); + PrintNodes(out, enode->Right); + out.Close(); } -static void PrintExprTrinary(FString &out, ZCC_TreeNode *node) +static void PrintExprTrinary(FLispString &out, ZCC_TreeNode *node) { ZCC_ExprTrinary *enode = (ZCC_ExprTrinary *)node; - out << "(expr-"; - PrintExprType(out, enode->Operation); + OpenExprType(out, enode->Operation); PrintNodes(out, enode->Test); PrintNodes(out, enode->Left); - PrintNodes(out, enode->Right, ')'); + PrintNodes(out, enode->Right); + out.Close(); } -static void PrintFuncParam(FString &out, ZCC_TreeNode *node) +static void PrintFuncParam(FLispString &out, ZCC_TreeNode *node) { ZCC_FuncParm *pnode = (ZCC_FuncParm *)node; - out.AppendFormat("(func-parm %s ", FName(pnode->Label).GetChars());; - PrintNodes(out, pnode->Value, ')'); + out.Open("func-parm"); + out.AddName(pnode->Label); + PrintNodes(out, pnode->Value); + out.Close(); } -static void PrintStatement(FString &out, ZCC_TreeNode *node) +static void PrintStatement(FLispString &out, ZCC_TreeNode *node) { - out << "(statement)"; + out.Open("statement"); + out.Close(); } -static void PrintCompoundStmt(FString &out, ZCC_TreeNode *node) +static void PrintCompoundStmt(FLispString &out, ZCC_TreeNode *node) { ZCC_CompoundStmt *snode = (ZCC_CompoundStmt *)node; - out << "(compound-stmt "; - PrintNodes(out, snode->Content, ')'); + out.Open("compound-stmt"); + PrintNodes(out, snode->Content); + out.Close(); } -static void PrintContinueStmt(FString &out, ZCC_TreeNode *node) +static void PrintContinueStmt(FLispString &out, ZCC_TreeNode *node) { - out << "(continue-stmt)"; + out.Open("continue-stmt"); + out.Close(); } -static void PrintBreakStmt(FString &out, ZCC_TreeNode *node) +static void PrintBreakStmt(FLispString &out, ZCC_TreeNode *node) { - out << "(break-stmt)"; + out.Open("break-stmt"); + out.Close(); } -static void PrintReturnStmt(FString &out, ZCC_TreeNode *node) +static void PrintReturnStmt(FLispString &out, ZCC_TreeNode *node) { ZCC_ReturnStmt *snode = (ZCC_ReturnStmt *)node; - out << "(return-stmt "; - PrintNodes(out, snode->Values, ')'); + out.Open("return-stmt"); + PrintNodes(out, snode->Values); + out.Close(); } -static void PrintExpressionStmt(FString &out, ZCC_TreeNode *node) +static void PrintExpressionStmt(FLispString &out, ZCC_TreeNode *node) { ZCC_ExpressionStmt *snode = (ZCC_ExpressionStmt *)node; - out << "(expression-stmt "; - PrintNodes(out, snode->Expression, ')'); + out.Open("expression-stmt"); + PrintNodes(out, snode->Expression); + out.Close(); } -static void PrintIterationStmt(FString &out, ZCC_TreeNode *node) +static void PrintIterationStmt(FLispString &out, ZCC_TreeNode *node) { ZCC_IterationStmt *snode = (ZCC_IterationStmt *)node; - out << "(iteration-stmt "; - out << (snode->CheckAt == ZCC_IterationStmt::Start) ? "start " : "end "; + out.Open("iteration-stmt"); + out.Add((snode->CheckAt == ZCC_IterationStmt::Start) ? "start" : "end"); PrintNodes(out, snode->LoopCondition); PrintNodes(out, snode->LoopBumper); - PrintNodes(out, snode->LoopStatement, true); + PrintNodes(out, snode->LoopStatement); + out.Close(); } -static void PrintIfStmt(FString &out, ZCC_TreeNode *node) +static void PrintIfStmt(FLispString &out, ZCC_TreeNode *node) { ZCC_IfStmt *snode = (ZCC_IfStmt *)node; - out << "(if-stmt "; + out.Open("if-stmt"); PrintNodes(out, snode->Condition); PrintNodes(out, snode->TruePath); - PrintNodes(out, snode->FalsePath, ')'); + PrintNodes(out, snode->FalsePath); + out.Close(); } -static void PrintSwitchStmt(FString &out, ZCC_TreeNode *node) +static void PrintSwitchStmt(FLispString &out, ZCC_TreeNode *node) { ZCC_SwitchStmt *snode = (ZCC_SwitchStmt *)node; - out << "(switch-stmt "; + out.Open("switch-stmt"); PrintNodes(out, snode->Condition); - PrintNodes(out, snode->Content, ')'); + PrintNodes(out, snode->Content); + out.Close(); } -static void PrintCaseStmt(FString &out, ZCC_TreeNode *node) +static void PrintCaseStmt(FLispString &out, ZCC_TreeNode *node) { ZCC_CaseStmt *snode = (ZCC_CaseStmt *)node; - out << "(case-stmt "; - PrintNodes(out, snode->Condition, ')'); + out.Open("case-stmt"); + PrintNodes(out, snode->Condition); + out.Close(); } -static void PrintAssignStmt(FString &out, ZCC_TreeNode *node) +static void BadAssignOp(FLispString &out, int op) +{ + char buf[32]; + size_t len = mysnprintf(buf, countof(buf), "assign-op-%d", op); + out.Add(buf, len); +} + +static void PrintAssignStmt(FLispString &out, ZCC_TreeNode *node) { ZCC_AssignStmt *snode = (ZCC_AssignStmt *)node; - out << "(assign-stmt "; + out.Open("assign-stmt"); switch (snode->AssignOp) { - case ZCC_EQ: out << "= "; break; - case ZCC_MULEQ: out << "*= "; break; - case ZCC_DIVEQ: out << "/= "; break; - case ZCC_MODEQ: out << "%= "; break; - case ZCC_ADDEQ: out << "+= "; break; - case ZCC_SUBEQ: out << "-= "; break; - case ZCC_LSHEQ: out << "<<= "; break; - case ZCC_RSHEQ: out << ">>= "; break; - case ZCC_ANDEQ: out << "&= "; break; - case ZCC_OREQ: out << "|= "; break; - case ZCC_XOREQ: out << "^= "; break; - default: - out.AppendFormat("assign-op-%d ", snode->AssignOp); + case ZCC_EQ: out.AddChar('='); break; + case ZCC_MULEQ: out.Add("*=", 2); break; + case ZCC_DIVEQ: out.Add("/=", 2); break; + case ZCC_MODEQ: out.Add("%=", 2); break; + case ZCC_ADDEQ: out.Add("+=", 2); break; + case ZCC_SUBEQ: out.Add("-=", 2); break; + case ZCC_LSHEQ: out.Add("<<=", 2); break; + case ZCC_RSHEQ: out.Add(">>=", 2); break; + case ZCC_ANDEQ: out.Add("&=", 2); break; + case ZCC_OREQ: out.Add("|=", 2); break; + case ZCC_XOREQ: out.Add("^=", 2); break; + default: BadAssignOp(out, snode->AssignOp); break; } PrintNodes(out, snode->Dests); - PrintNodes(out, snode->Sources, ')'); + PrintNodes(out, snode->Sources); + out.Close(); } -static void PrintLocalVarStmt(FString &out, ZCC_TreeNode *node) +static void PrintLocalVarStmt(FLispString &out, ZCC_TreeNode *node) { ZCC_LocalVarStmt *snode = (ZCC_LocalVarStmt *)node; - out << "(local-var-stmt "; + out.Open("local-var-stmt"); PrintNodes(out, snode->Type); PrintNodes(out, snode->Vars); - PrintNodes(out, snode->Inits, ')'); + PrintNodes(out, snode->Inits); + out.Close(); } -static void PrintFuncParamDecl(FString &out, ZCC_TreeNode *node) +static void PrintFuncParamDecl(FLispString &out, ZCC_TreeNode *node) { ZCC_FuncParamDecl *dnode = (ZCC_FuncParamDecl *)node; - out << "(func-param-decl "; + out.Open("func-param-decl"); PrintNodes(out, dnode->Type); - out.AppendFormat("%s %x)", FName(dnode->Name).GetChars(), dnode->Flags); + out.AddName(dnode->Name); + out.AddHex(dnode->Flags); + out.Close(); } -static void PrintConstantDef(FString &out, ZCC_TreeNode *node) +static void PrintConstantDef(FLispString &out, ZCC_TreeNode *node) { ZCC_ConstantDef *dnode = (ZCC_ConstantDef *)node; - out.AppendFormat("(constant-def %s ", FName(dnode->Name).GetChars()); - PrintNodes(out, dnode->Value, ')'); + out.Open("constant-def"); + out.AddName(dnode->Name); + PrintNodes(out, dnode->Value); + out.Close(); } -static void PrintDeclarator(FString &out, ZCC_TreeNode *node) +static void PrintDeclarator(FLispString &out, ZCC_TreeNode *node) { ZCC_Declarator *dnode = (ZCC_Declarator *)node; - out << "(declarator "; + out.Open("declarator"); PrintNodes(out, dnode->Type); - out.AppendFormat("%x)", dnode->Flags); + out.AddHex(dnode->Flags); + out.Close(); } -static void PrintVarDeclarator(FString &out, ZCC_TreeNode *node) +static void PrintVarDeclarator(FLispString &out, ZCC_TreeNode *node) { ZCC_VarDeclarator *dnode = (ZCC_VarDeclarator *)node; - out << "\n(var-declarator "; + out.Break(); + out.Open("var-declarator"); PrintNodes(out, dnode->Type); - out.AppendFormat("%x ", dnode->Flags); - PrintNodes(out, dnode->Names, ')'); - out << '\n'; + out.AddHex(dnode->Flags); + PrintNodes(out, dnode->Names); + out.Close(); } -static void PrintFuncDeclarator(FString &out, ZCC_TreeNode *node) +static void PrintFuncDeclarator(FLispString &out, ZCC_TreeNode *node) { ZCC_FuncDeclarator *dnode = (ZCC_FuncDeclarator *)node; - out << "\n(func-declarator "; + out.Break(); + out.Open("func-declarator"); PrintNodes(out, dnode->Type); - out.AppendFormat("%x %s ", dnode->Flags, FName(dnode->Name).GetChars()); - PrintNodes(out, dnode->Params, ' '); - PrintNodes(out, dnode->Body, ')'); - out << '\n'; + out.AddHex(dnode->Flags); + out.AddName(dnode->Name); + PrintNodes(out, dnode->Params); + PrintNodes(out, dnode->Body); + out.Close(); } -void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FString &, ZCC_TreeNode *) = +void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode *) = { PrintIdentifier, PrintClass, @@ -607,7 +794,7 @@ void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FString &, ZCC_TreeNode *) = FString ZCC_PrintAST(ZCC_TreeNode *root) { - FString out; - PrintNodes(out, root, '\0'); + FLispString out; + PrintNodes(out, root); return out; } From c733e4229aaaa9d121a331cf0fa0d0dfd95f519b Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 17 Jul 2013 23:22:13 -0500 Subject: [PATCH 087/232] Added more linebreaks to AST dumps --- src/zscript/ast.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/zscript/ast.cpp b/src/zscript/ast.cpp index 42917eb07..e11d7fb32 100644 --- a/src/zscript/ast.cpp +++ b/src/zscript/ast.cpp @@ -234,6 +234,7 @@ static void PrintStringConst(FLispString &out, FString str) static void PrintClass(FLispString &out, ZCC_TreeNode *node) { ZCC_Class *cnode = (ZCC_Class *)node; + out.Break(); out.Open("class"); PrintNodes(out, cnode->ClassName); PrintNodes(out, cnode->ParentName); @@ -561,6 +562,7 @@ static void PrintExprTrinary(FLispString &out, ZCC_TreeNode *node) static void PrintFuncParam(FLispString &out, ZCC_TreeNode *node) { ZCC_FuncParm *pnode = (ZCC_FuncParm *)node; + out.Break(); out.Open("func-parm"); out.AddName(pnode->Label); PrintNodes(out, pnode->Value); @@ -576,6 +578,7 @@ static void PrintStatement(FLispString &out, ZCC_TreeNode *node) static void PrintCompoundStmt(FLispString &out, ZCC_TreeNode *node) { ZCC_CompoundStmt *snode = (ZCC_CompoundStmt *)node; + out.Break(); out.Open("compound-stmt"); PrintNodes(out, snode->Content); out.Close(); @@ -583,12 +586,14 @@ static void PrintCompoundStmt(FLispString &out, ZCC_TreeNode *node) static void PrintContinueStmt(FLispString &out, ZCC_TreeNode *node) { + out.Break(); out.Open("continue-stmt"); out.Close(); } static void PrintBreakStmt(FLispString &out, ZCC_TreeNode *node) { + out.Break(); out.Open("break-stmt"); out.Close(); } @@ -596,6 +601,7 @@ static void PrintBreakStmt(FLispString &out, ZCC_TreeNode *node) static void PrintReturnStmt(FLispString &out, ZCC_TreeNode *node) { ZCC_ReturnStmt *snode = (ZCC_ReturnStmt *)node; + out.Break(); out.Open("return-stmt"); PrintNodes(out, snode->Values); out.Close(); @@ -604,6 +610,7 @@ static void PrintReturnStmt(FLispString &out, ZCC_TreeNode *node) static void PrintExpressionStmt(FLispString &out, ZCC_TreeNode *node) { ZCC_ExpressionStmt *snode = (ZCC_ExpressionStmt *)node; + out.Break(); out.Open("expression-stmt"); PrintNodes(out, snode->Expression); out.Close(); @@ -612,6 +619,7 @@ static void PrintExpressionStmt(FLispString &out, ZCC_TreeNode *node) static void PrintIterationStmt(FLispString &out, ZCC_TreeNode *node) { ZCC_IterationStmt *snode = (ZCC_IterationStmt *)node; + out.Break(); out.Open("iteration-stmt"); out.Add((snode->CheckAt == ZCC_IterationStmt::Start) ? "start" : "end"); PrintNodes(out, snode->LoopCondition); @@ -623,9 +631,12 @@ static void PrintIterationStmt(FLispString &out, ZCC_TreeNode *node) static void PrintIfStmt(FLispString &out, ZCC_TreeNode *node) { ZCC_IfStmt *snode = (ZCC_IfStmt *)node; + out.Break(); out.Open("if-stmt"); PrintNodes(out, snode->Condition); + out.Break(); PrintNodes(out, snode->TruePath); + out.Break(); PrintNodes(out, snode->FalsePath); out.Close(); } @@ -633,8 +644,10 @@ static void PrintIfStmt(FLispString &out, ZCC_TreeNode *node) static void PrintSwitchStmt(FLispString &out, ZCC_TreeNode *node) { ZCC_SwitchStmt *snode = (ZCC_SwitchStmt *)node; + out.Break(); out.Open("switch-stmt"); PrintNodes(out, snode->Condition); + out.Break(); PrintNodes(out, snode->Content); out.Close(); } @@ -642,6 +655,7 @@ static void PrintSwitchStmt(FLispString &out, ZCC_TreeNode *node) static void PrintCaseStmt(FLispString &out, ZCC_TreeNode *node) { ZCC_CaseStmt *snode = (ZCC_CaseStmt *)node; + out.Break(); out.Open("case-stmt"); PrintNodes(out, snode->Condition); out.Close(); @@ -691,6 +705,7 @@ static void PrintLocalVarStmt(FLispString &out, ZCC_TreeNode *node) static void PrintFuncParamDecl(FLispString &out, ZCC_TreeNode *node) { ZCC_FuncParamDecl *dnode = (ZCC_FuncParamDecl *)node; + out.Break(); out.Open("func-param-decl"); PrintNodes(out, dnode->Type); out.AddName(dnode->Name); @@ -701,6 +716,7 @@ static void PrintFuncParamDecl(FLispString &out, ZCC_TreeNode *node) static void PrintConstantDef(FLispString &out, ZCC_TreeNode *node) { ZCC_ConstantDef *dnode = (ZCC_ConstantDef *)node; + out.Break(); out.Open("constant-def"); out.AddName(dnode->Name); PrintNodes(out, dnode->Value); @@ -710,6 +726,7 @@ static void PrintConstantDef(FLispString &out, ZCC_TreeNode *node) static void PrintDeclarator(FLispString &out, ZCC_TreeNode *node) { ZCC_Declarator *dnode = (ZCC_Declarator *)node; + out.Break(); out.Open("declarator"); PrintNodes(out, dnode->Type); out.AddHex(dnode->Flags); From 9cf9226e86a1d775e3a1a5d11c44c48247947abd Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 17 Jul 2013 23:36:10 -0500 Subject: [PATCH 088/232] Don't leave open parentheses hanging at line breaks --- src/zscript/ast.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/zscript/ast.cpp b/src/zscript/ast.cpp index e11d7fb32..bc1afd312 100644 --- a/src/zscript/ast.cpp +++ b/src/zscript/ast.cpp @@ -34,6 +34,7 @@ public: NestDepth = Column = 0; WrapWidth = 72; NeedSpace = false; + ConsecOpens = 0; } void Open(const char *label) @@ -43,8 +44,10 @@ public: if (NeedSpace) { Str << ' '; + ConsecOpens = 0; } Str << '('; + ConsecOpens++; if (label != NULL) { Str.AppendCStrPart(label, labellen); @@ -66,6 +69,15 @@ public: // Don't break if not needed. if (Column != NestDepth) { + if (NeedSpace) + { + ConsecOpens = 0; + } + else + { // Move hanging ( characters to the new line + Str.Truncate(long(Str.Len() - ConsecOpens)); + NestDepth -= ConsecOpens; + } Str << '\n'; Column = NestDepth; NeedSpace = false; @@ -73,6 +85,14 @@ public: { Str.AppendFormat("%*s", NestDepth, ""); } + if (ConsecOpens > 0) + { + for (size_t i = 0; i < ConsecOpens; ++i) + { + Str << '('; + } + NestDepth += ConsecOpens; + } } } bool CheckWrap(size_t len) @@ -143,6 +163,7 @@ private: size_t NestDepth; size_t Column; size_t WrapWidth; + size_t ConsecOpens; bool NeedSpace; }; From 733e5fa2e1c55d9acdc69b7ec6f236822efb2bea Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 19 Jul 2013 23:25:01 -0500 Subject: [PATCH 089/232] Recognize C-style array declarations - The variable_name production now accepts an optional array size argument. (Not yet passed to the AST.) - The notation for using dotted ID lists as types has been changed from [id1.id2] to .id1.id2, beacuse the former conflicts with the notation for arrays. --- src/zscript/zcc-parse.lemon | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index 6c461cc50..41c605300 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -402,7 +402,7 @@ type_name(X) ::= IDENTIFIER(A). /* User-defined type (struct, enum, or class) id->Id = A.Name(); X = type; } -type_name(X) ::= LBRACKET dottable_id(A) RBRACKET. +type_name(X) ::= DOT dottable_id(A). { NEW_AST_NODE(BasicType, type); type->Type = ZCC_UserType; @@ -441,6 +441,7 @@ vector_size(X) ::= LT INTCONST(A) GT. %type type_or_array {ZCC_Type *} %type class_restrictor {ZCC_Identifier *} %type array_size{ZCC_Expression *} +%type array_size_expr{ZCC_Expression *} aggregate_type(X) ::= MAP LT type_or_array(A) COMMA type_or_array(B) GT. /* Hash table */ { @@ -478,7 +479,7 @@ type_list(X) ::= type_list(A) COMMA type_or_array(B). { X = A; A->AppendSibling( type_list_or_void(X) ::= VOID. { X = NULL; } type_list_or_void(X) ::= type_list(A). { X = A; } -array_size(X) ::= LBRACKET opt_expr(A) RBRACKET. +array_size_expr(X) ::= LBRACKET opt_expr(A) RBRACKET. { if (A == NULL) { @@ -491,18 +492,13 @@ array_size(X) ::= LBRACKET opt_expr(A) RBRACKET. X = A; } } -array_size(X) ::= array_size(A) LBRACKET opt_expr(B) RBRACKET. +array_size(X) ::= array_size_expr(A). { - if (B == NULL) - { - NEW_AST_NODE(Expression,nil); - nil->Operation = PEX_Nil; - A->AppendSibling(nil); - } - else - { - A->AppendSibling(B); - } + X = A; +} +array_size(X) ::= array_size(A) array_size_expr(B). +{ + A->AppendSibling(B); X = A; } @@ -613,6 +609,12 @@ variable_name(X) ::= IDENTIFIER(A). var->Name = ENamedName(A.Int); X = var; } +variable_name(X) ::= IDENTIFIER(A) array_size. +{ + NEW_AST_NODE(VarName,var); + var->Name = ENamedName(A.Int); + X = var; +} variable_list(X) ::= variable_name(A). { From aadd4e4de6b3214a1d199af4ff28d949e2b83fb7 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 23 Jul 2013 18:38:57 -0500 Subject: [PATCH 090/232] ZCCParseNode needs to initialize TopNode - If the parsing is a complete failure, then TopNode won't ever be set to anything during the parsing process. --- src/zscript/zcc_parser.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index eaaba6192..8d3f9bab9 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -2,6 +2,7 @@ struct ZCCParseState { ZCCParseState(FScanner &scanner) : sc(scanner) { + TopNode = NULL; } FScanner ≻ From 46c0127ebb141de3ef9b3f00dc070829f2e7b9a3 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 23 Jul 2013 19:28:58 -0500 Subject: [PATCH 091/232] Don't accept function params starting with a comma - Fixed: func_expr_list would accept nonsense like this: Myfunction(, 1, 2); --- src/zscript/zcc-parse.lemon | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index 41c605300..ed25532ca 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -991,17 +991,22 @@ expr_list(X) ::= expr_list(A) COMMA expr(B). * 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 func_expr_list1{ZCC_FuncParm *} %type named_expr{ZCC_FuncParm *} func_expr_list(X) ::= . { X = NULL; } -func_expr_list(X) ::= named_expr(A). +func_expr_list(X) ::= func_expr_list1(A). { X = A; } -func_expr_list(X) ::= func_expr_list(A) COMMA named_expr(B). +func_expr_list1(X) ::= named_expr(A). +{ + X = A; +} +func_expr_list1(X) ::= func_expr_list1(A) COMMA named_expr(B). { X = A; A->AppendSibling(B); From 0d25ed82896348f48ae60d89ace6dbea87244136 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 23 Jul 2013 19:34:21 -0500 Subject: [PATCH 092/232] state_call needs parenthesis around func_expr_list - Fixed: state_call needs to enclose func_expr_list in LPAREN/RPAREN itself, because func_expr_list doesn't include them. This means it also needs a separate production to accept calls without a parameter list. --- src/zscript/zcc-parse.lemon | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index ed25532ca..92eb4d25e 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -256,6 +256,7 @@ enumerator(X) ::= IDENTIFIER(A) EQ expr(B). /* Expression must be constant. */ %type state_goto_offset {ZCC_Expression *} %type state_action {ZCC_TreeNode *} %type state_call {ZCC_ExprFuncCall *} +%type state_call_params {ZCC_FuncParm *} %include { struct StateOpts { @@ -348,7 +349,7 @@ state_action(X) ::= LBRACE error scanner_mode RBRACE. { X = NULL; } state_action(X) ::= state_call(A) scanner_mode SEMICOLON. { X = A; } state_call(X) ::= . { X = NULL; } -state_call(X) ::= IDENTIFIER(A) func_expr_list(B). +state_call(X) ::= IDENTIFIER(A) state_call_params(B). { NEW_AST_NODE(ExprFuncCall, expr); NEW_AST_NODE(ExprID, func); @@ -361,6 +362,9 @@ state_call(X) ::= IDENTIFIER(A) func_expr_list(B). X = expr; } +state_call_params(X) ::= . { X = NULL; } +state_call_params(X) ::= LPAREN func_expr_list(A) RPAREN. { X = A; } + /* Definition of a default class instance. */ %type default_def {ZCC_CompoundStmt *} default_def(X) ::= DEFAULT compound_statement(A). { X = A; } From 67caf3303b7edbd9e8859a88b8d9d4fff74944e3 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 23 Jul 2013 19:59:47 -0500 Subject: [PATCH 093/232] Add the array size to ZCC_VarName --- src/zscript/ast.cpp | 1 + src/zscript/zcc-parse.lemon | 4 +++- src/zscript/zcc_parser.h | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/zscript/ast.cpp b/src/zscript/ast.cpp index bc1afd312..7908a50c5 100644 --- a/src/zscript/ast.cpp +++ b/src/zscript/ast.cpp @@ -373,6 +373,7 @@ static void PrintVarName(FLispString &out, ZCC_TreeNode *node) ZCC_VarName *vnode = (ZCC_VarName *)node; out.Open("var-name"); out.AddName(vnode->Name); + PrintNodes(out, vnode->ArraySize); out.Close(); } diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index 92eb4d25e..c41b3671e 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -611,12 +611,14 @@ variable_name(X) ::= IDENTIFIER(A). { NEW_AST_NODE(VarName,var); var->Name = ENamedName(A.Int); + var->ArraySize = NULL; X = var; } -variable_name(X) ::= IDENTIFIER(A) array_size. +variable_name(X) ::= IDENTIFIER(A) array_size(B). { NEW_AST_NODE(VarName,var); var->Name = ENamedName(A.Int); + var->ArraySize = B; X = var; } diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index 8d3f9bab9..a1f093482 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -307,6 +307,7 @@ struct ZCC_StateLine : ZCC_StatePart struct ZCC_VarName : ZCC_TreeNode { ENamedName Name; + ZCC_Expression *ArraySize; // NULL if not an array }; struct ZCC_Type : ZCC_TreeNode From a136ca65ea6c116ac80182e1c8d679801981cf24 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 23 Jul 2013 20:43:15 -0500 Subject: [PATCH 094/232] Allow functions without parameters - Fixed: Trying to define a function without any parameters would silently discard the function, because the declarator tested FuncParams instead of FuncName to decide if it was a function. --- src/zscript/zcc-parse.lemon | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index c41b3671e..b1420c893 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -522,11 +522,11 @@ array_size(X) ::= array_size(A) array_size_expr(B). /* Multiple type names are only valid for functions. */ declarator(X) ::= decl_flags(A) type_list_or_void(B) variables_or_function(C). { - if (C.FuncParams == NULL && C.VarNames == NULL) + if (C.FuncName == NAME_None && C.VarNames == NULL) { // An error. A message was already printed. X = NULL; } - else if (C.FuncParams != NULL) + else if (C.FuncName != NAME_None) { // A function NEW_AST_NODE(FuncDeclarator, decl); decl->Type = B; From 7d304a4cb618192987a2c4fe4a19470fe2b5c0c7 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 24 Jul 2013 20:59:29 -0500 Subject: [PATCH 095/232] Partially revert commit 46c0127 - Being able to omit optional function arguments is not such a nonsensical thing after all. However, the previous grammar was still inadequate for representing this in a useful way. --- src/zscript/zcc-parse.lemon | 40 ++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index b1420c893..3090125aa 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -997,26 +997,42 @@ expr_list(X) ::= expr_list(A) COMMA expr(B). * 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 func_expr_list1{ZCC_FuncParm *} +%type func_expr_item{ZCC_FuncParm *} %type named_expr{ZCC_FuncParm *} -func_expr_list(X) ::= . +func_expr_list(X) ::= func_expr_item(A). +{ + X = A; +} +func_expr_list(X) ::= func_expr_list(A) COMMA func_expr_item(B). +{ + // Omitted parameters still need to appear as nodes in the list. + if (A == NULL) + { + NEW_AST_NODE(FuncParm,nil_a); + nil_a->Value = NULL; + nil_a->Label = NAME_None; + A = nil_a; + } + if (B == NULL) + { + NEW_AST_NODE(FuncParm,nil_b); + nil_b->Value = NULL; + nil_b->Label = NAME_None; + B = nil_b; + } + X = A; + A->AppendSibling(B); +} + +func_expr_item(X) ::= . { X = NULL; } -func_expr_list(X) ::= func_expr_list1(A). +func_expr_item(X) ::= named_expr(A). { X = A; } -func_expr_list1(X) ::= named_expr(A). -{ - X = A; -} -func_expr_list1(X) ::= func_expr_list1(A) COMMA named_expr(B). -{ - X = A; - A->AppendSibling(B); -} named_expr(X) ::= IDENTIFIER(A) COLON expr(B). { From f6bbd5abf793f543d32c3850dc0fc87919004a3d Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 24 Jul 2013 21:35:02 -0500 Subject: [PATCH 096/232] Simplify AST dumps. - More forced line breaks. - Don't use extra parentheses in places where it can still be unambiguous without them. - Don't print the UserType for basic-types that aren't ZCC_UserType. --- src/zscript/ast.cpp | 66 +++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/src/zscript/ast.cpp b/src/zscript/ast.cpp index 7908a50c5..ae687eefc 100644 --- a/src/zscript/ast.cpp +++ b/src/zscript/ast.cpp @@ -182,7 +182,7 @@ static void PrintNode(FLispString &out, ZCC_TreeNode *node) } } -static void PrintNodes(FLispString &out, ZCC_TreeNode *node) +static void PrintNodes(FLispString &out, ZCC_TreeNode *node, bool newlist=true, bool addbreaks=false) { ZCC_TreeNode *p; @@ -192,14 +192,24 @@ static void PrintNodes(FLispString &out, ZCC_TreeNode *node) } else { - out.Open(NULL); + if (newlist) + { + out.Open(NULL); + } p = node; do { + if (addbreaks) + { + out.Break(); + } PrintNode(out, p); p = p->SiblingNext; } while (p != node); - out.Close(); + if (newlist) + { + out.Close(); + } } } @@ -261,7 +271,7 @@ static void PrintClass(FLispString &out, ZCC_TreeNode *node) PrintNodes(out, cnode->ParentName); PrintNodes(out, cnode->Replaces); out.AddHex(cnode->Flags); - PrintNodes(out, cnode->Body); + PrintNodes(out, cnode->Body, false, true); out.Close(); } @@ -271,7 +281,7 @@ static void PrintStruct(FLispString &out, ZCC_TreeNode *node) out.Break(); out.Open("struct"); out.AddName(snode->StructName); - PrintNodes(out, snode->Body); + PrintNodes(out, snode->Body, false, true); out.Close(); } @@ -282,7 +292,7 @@ static void PrintEnum(FLispString &out, ZCC_TreeNode *node) out.Open("enum"); out.AddName(enode->EnumName); PrintBuiltInType(out, enode->EnumType); - PrintNodes(out, enode->Elements); + PrintNodes(out, enode->Elements, false, true); out.Close(); } @@ -291,7 +301,7 @@ static void PrintEnumNode(FLispString &out, ZCC_TreeNode *node) ZCC_EnumNode *enode = (ZCC_EnumNode *)node; out.Open("enum-node"); out.AddName(enode->ElemName); - PrintNodes(out, enode->ElemValue); + PrintNodes(out, enode->ElemValue, false); out.Close(); } @@ -300,7 +310,7 @@ static void PrintStates(FLispString &out, ZCC_TreeNode *node) ZCC_States *snode = (ZCC_States *)node; out.Break(); out.Open("states"); - PrintNodes(out, snode->Body); + PrintNodes(out, snode->Body, false, true); out.Close(); } @@ -313,7 +323,6 @@ static void PrintStatePart(FLispString &out, ZCC_TreeNode *node) static void PrintStateLabel(FLispString &out, ZCC_TreeNode *node) { ZCC_StateLabel *snode = (ZCC_StateLabel *)node; - out.Break(); out.Open("state-label"); out.AddName(snode->Label); out.Close(); @@ -355,7 +364,6 @@ static void PrintStateGoto(FLispString &out, ZCC_TreeNode *node) static void PrintStateLine(FLispString &out, ZCC_TreeNode *node) { ZCC_StateLine *snode = (ZCC_StateLine *)node; - out.Break(); out.Open("state-line"); out.Add(snode->Sprite, 4); if (snode->bBright) @@ -364,7 +372,7 @@ static void PrintStateLine(FLispString &out, ZCC_TreeNode *node) } out.Add(*(snode->Frames)); PrintNodes(out, snode->Offset); - PrintNodes(out, snode->Action); + PrintNodes(out, snode->Action, false); out.Close(); } @@ -372,8 +380,8 @@ static void PrintVarName(FLispString &out, ZCC_TreeNode *node) { ZCC_VarName *vnode = (ZCC_VarName *)node; out.Open("var-name"); - out.AddName(vnode->Name); PrintNodes(out, vnode->ArraySize); + out.AddName(vnode->Name); out.Close(); } @@ -391,7 +399,10 @@ static void PrintBasicType(FLispString &out, ZCC_TreeNode *node) out.Open("basic-type"); PrintNodes(out, tnode->ArraySize); PrintBuiltInType(out, tnode->Type); - PrintNodes(out, tnode->UserType); + if (tnode->Type == ZCC_UserType) + { + PrintNodes(out, tnode->UserType, false); + } out.Close(); } @@ -540,7 +551,7 @@ static void PrintExprFuncCall(FLispString &out, ZCC_TreeNode *node) assert(enode->Operation == PEX_FuncCall); out.Open("expr-func-call"); PrintNodes(out, enode->Function); - PrintNodes(out, enode->Parameters); + PrintNodes(out, enode->Parameters, false); out.Close(); } @@ -558,7 +569,7 @@ static void PrintExprUnary(FLispString &out, ZCC_TreeNode *node) { ZCC_ExprUnary *enode = (ZCC_ExprUnary *)node; OpenExprType(out, enode->Operation); - PrintNodes(out, enode->Operand); + PrintNodes(out, enode->Operand, false); out.Close(); } @@ -587,7 +598,7 @@ static void PrintFuncParam(FLispString &out, ZCC_TreeNode *node) out.Break(); out.Open("func-parm"); out.AddName(pnode->Label); - PrintNodes(out, pnode->Value); + PrintNodes(out, pnode->Value, false); out.Close(); } @@ -602,7 +613,7 @@ static void PrintCompoundStmt(FLispString &out, ZCC_TreeNode *node) ZCC_CompoundStmt *snode = (ZCC_CompoundStmt *)node; out.Break(); out.Open("compound-stmt"); - PrintNodes(out, snode->Content); + PrintNodes(out, snode->Content, false, true); out.Close(); } @@ -625,7 +636,7 @@ static void PrintReturnStmt(FLispString &out, ZCC_TreeNode *node) ZCC_ReturnStmt *snode = (ZCC_ReturnStmt *)node; out.Break(); out.Open("return-stmt"); - PrintNodes(out, snode->Values); + PrintNodes(out, snode->Values, false); out.Close(); } @@ -634,7 +645,7 @@ static void PrintExpressionStmt(FLispString &out, ZCC_TreeNode *node) ZCC_ExpressionStmt *snode = (ZCC_ExpressionStmt *)node; out.Break(); out.Open("expression-stmt"); - PrintNodes(out, snode->Expression); + PrintNodes(out, snode->Expression, false); out.Close(); } @@ -644,8 +655,11 @@ static void PrintIterationStmt(FLispString &out, ZCC_TreeNode *node) out.Break(); out.Open("iteration-stmt"); out.Add((snode->CheckAt == ZCC_IterationStmt::Start) ? "start" : "end"); + out.Break(); PrintNodes(out, snode->LoopCondition); + out.Break(); PrintNodes(out, snode->LoopBumper); + out.Break(); PrintNodes(out, snode->LoopStatement); out.Close(); } @@ -670,7 +684,7 @@ static void PrintSwitchStmt(FLispString &out, ZCC_TreeNode *node) out.Open("switch-stmt"); PrintNodes(out, snode->Condition); out.Break(); - PrintNodes(out, snode->Content); + PrintNodes(out, snode->Content, false); out.Close(); } @@ -679,7 +693,7 @@ static void PrintCaseStmt(FLispString &out, ZCC_TreeNode *node) ZCC_CaseStmt *snode = (ZCC_CaseStmt *)node; out.Break(); out.Open("case-stmt"); - PrintNodes(out, snode->Condition); + PrintNodes(out, snode->Condition, false); out.Close(); } @@ -741,7 +755,7 @@ static void PrintConstantDef(FLispString &out, ZCC_TreeNode *node) out.Break(); out.Open("constant-def"); out.AddName(dnode->Name); - PrintNodes(out, dnode->Value); + PrintNodes(out, dnode->Value, false); out.Close(); } @@ -750,8 +764,8 @@ static void PrintDeclarator(FLispString &out, ZCC_TreeNode *node) ZCC_Declarator *dnode = (ZCC_Declarator *)node; out.Break(); out.Open("declarator"); - PrintNodes(out, dnode->Type); out.AddHex(dnode->Flags); + PrintNodes(out, dnode->Type); out.Close(); } @@ -760,8 +774,8 @@ static void PrintVarDeclarator(FLispString &out, ZCC_TreeNode *node) ZCC_VarDeclarator *dnode = (ZCC_VarDeclarator *)node; out.Break(); out.Open("var-declarator"); - PrintNodes(out, dnode->Type); out.AddHex(dnode->Flags); + PrintNodes(out, dnode->Type); PrintNodes(out, dnode->Names); out.Close(); } @@ -771,11 +785,11 @@ static void PrintFuncDeclarator(FLispString &out, ZCC_TreeNode *node) ZCC_FuncDeclarator *dnode = (ZCC_FuncDeclarator *)node; out.Break(); out.Open("func-declarator"); - PrintNodes(out, dnode->Type); out.AddHex(dnode->Flags); + PrintNodes(out, dnode->Type); out.AddName(dnode->Name); PrintNodes(out, dnode->Params); - PrintNodes(out, dnode->Body); + PrintNodes(out, dnode->Body, false); out.Close(); } From e3e32d7cca2694bc87cc8a9a19202383ebd2126d Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Thu, 25 Jul 2013 21:41:18 -0500 Subject: [PATCH 097/232] Added DeleteAndClear method to TDeletingArray. - Normally, TDeletingArray only deletes its contents when it is destroyed. Now you can do it earlier if you want. --- src/tarray.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/tarray.h b/src/tarray.h index 3e66aa748..57de62984 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -371,6 +371,15 @@ public: delete (*this)[i]; } } + void DeleteAndClear() + { + for (unsigned int i = 0; i < TArray<T,TT>::Size(); ++i) + { + if ((*this)[i] != NULL) + delete (*this)[i]; + } + Clear(); + } }; // TAutoGrowArray ----------------------------------------------------------- From 070c0a9e3057eac42453b974ebb4031671b5619c Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Thu, 25 Jul 2013 21:42:30 -0500 Subject: [PATCH 098/232] Stop leaking function damage expressions. - Function damage expressions parsed from DECORATE are now stored in a single array and deleted at the end of FinishThingdef(). --- src/thingdef/thingdef.cpp | 8 +++++++- src/thingdef/thingdef.h | 1 + src/thingdef/thingdef_properties.cpp | 9 ++++++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 8a3589a99..36c09d716 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -66,6 +66,8 @@ #include "vmbuilder.h" #include "stats.h" +TDeletingArray<class FxExpression *> ActorDamageFuncs; + // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- void InitThingdef(); void ParseDecorate (FScanner &sc); @@ -351,8 +353,8 @@ static void FinishThingdef() if (def->Damage != NULL) { + FxDamageValue *dmg = (FxDamageValue *)ActorDamageFuncs[(uintptr_t)def->Damage - 1]; VMScriptFunction *sfunc; - FxDamageValue *dmg = (FxDamageValue *)def->Damage; sfunc = dmg->GetFunction(); if (sfunc == NULL) { @@ -389,6 +391,9 @@ static void FinishThingdef() I_Error("%d errors during actor postprocessing", errorcount); } + ActorDamageFuncs.DeleteAndClear(); + StateTempCalls.DeleteAndClear(); + // Since these are defined in DECORATE now the table has to be initialized here. for(int i = 0; i < 31; i++) { @@ -415,6 +420,7 @@ void LoadActors () timer.Reset(); timer.Clock(); StateParams.Clear(); + ActorDamageFuncs.Clear(); GlobalSymbols.ReleaseSymbols(); FScriptPosition::ResetErrorCounter(); InitThingdef(); diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index 76479bc4d..b65bb4637 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -154,6 +154,7 @@ public: extern FStateExpressions StateParams; +extern TDeletingArray<class FxExpression *> ActorDamageFuncs; //========================================================================== // diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index b1df39d90..12cb318b1 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -544,7 +544,14 @@ DEFINE_PROPERTY(damage, X, Actor) // Store this expression here for now. It will be converted to a function // later once all actors have been processed. - defaults->Damage = (VMFunction *)id; + if (id == NULL) + { + defaults->Damage = NULL; + } + else + { + defaults->Damage = (VMFunction *)(uintptr_t)(ActorDamageFuncs.Push(id) + 1); + } } //========================================================================== From 57bb9c2f7afba9f5dfbcc3d3e09eb5a5fcc31160 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Thu, 25 Jul 2013 22:29:59 -0500 Subject: [PATCH 099/232] Better disassembly of FLOP instructions. - Annotate FLOP instructions with the name of the floating point operation indicated by the C field. --- src/zscript/vmdisasm.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/zscript/vmdisasm.cpp b/src/zscript/vmdisasm.cpp index d2e87956d..3cfcd821d 100644 --- a/src/zscript/vmdisasm.cpp +++ b/src/zscript/vmdisasm.cpp @@ -97,6 +97,27 @@ const VMOpInfo OpInfo[NUM_OPS] = #include "vmops.h" }; +static const char *const FlopNames[] = +{ + "abs", + "neg", + "acos", + "asin", + "atan", + "cos", + "cosh", + "exp", + "log", + "log10", + "sin", + "sinh", + "tan", + "tanh", + "sqrt", + "ceil", + "floor" +}; + static int print_reg(FILE *out, int col, int arg, int mode, int immshift, const VMScriptFunction *func); static int printf_wrapper(FILE *f, const char *fmt, ...) @@ -263,6 +284,14 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction } break; + case OP_FLOP: + col = printf_wrapper(out, "f%d,f%d,%d", code[i].a, code[i].b, code[i].c); + if (code[i].c < countof(FlopNames)) + { + col +=printf_wrapper(out, " [%s]", FlopNames[code[i].c]); + } + break; + default: if ((mode & MODE_BCTYPE) == MODE_BCCAST) { From 0603295822a8d19e5cec0832c583711ee1cc0634 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 27 Jul 2013 21:35:22 -0500 Subject: [PATCH 100/232] Added EmitParamInt to VMFunctionBuilder --- src/zscript/vmbuilder.cpp | 22 ++++++++++++++++++++++ src/zscript/vmbuilder.h | 1 + 2 files changed, 23 insertions(+) diff --git a/src/zscript/vmbuilder.cpp b/src/zscript/vmbuilder.cpp index c87ff636a..4a3462c4f 100644 --- a/src/zscript/vmbuilder.cpp +++ b/src/zscript/vmbuilder.cpp @@ -468,6 +468,28 @@ size_t VMFunctionBuilder::Emit(int opcode, int opabc) return Code.Push(op); } +//========================================================================== +// +// VMFunctionBuilder :: EmitParamInt +// +// Passes a constant integer parameter, using either PARAMI and an immediate +// value or PARAM and a constant register, as appropriate. +// +//========================================================================== + +size_t VMFunctionBuilder::EmitParamInt(int value) +{ + // Immediates for PARAMI must fit in 24 bits. + if (((value << 8) >> 8) == value) + { + return Emit(OP_PARAMI, value); + } + else + { + return Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, GetConstantInt(value)); + } +} + //========================================================================== // // VMFunctionBuilder :: EmitLoadInt diff --git a/src/zscript/vmbuilder.h b/src/zscript/vmbuilder.h index 7587d1b20..c15f65739 100644 --- a/src/zscript/vmbuilder.h +++ b/src/zscript/vmbuilder.h @@ -36,6 +36,7 @@ public: size_t Emit(int opcode, int opa, int opb, int opc); size_t Emit(int opcode, int opa, VM_SHALF opbc); size_t Emit(int opcode, int opabc); + size_t EmitParamInt(int value); size_t EmitLoadInt(int regnum, int value); size_t EmitRetInt(int retnum, bool final, int value); From 6cf0916f720cc470975a2a325269652a4006083e Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 27 Jul 2013 21:38:35 -0500 Subject: [PATCH 101/232] Use VMFunctionBuilder::EmitParamInt in thingdef_expression.cpp --- src/thingdef/thingdef_expression.cpp | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index e05172d02..bd2dfe70e 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -320,19 +320,6 @@ FxExpression *FxParameter::Resolve(FCompileContext& ctx) return this; } -static void EmitConstantInt(VMFunctionBuilder *build, int val) -{ - // If it fits in 24 bits, use PARAMI instead of PARAM. - if (((val << 8) >> 8) == val) - { - build->Emit(OP_PARAMI, val); - } - else - { - build->Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, build->GetConstantInt(val)); - } -} - ExpEmit FxParameter::Emit(VMFunctionBuilder *build) { if (Operand->isConstant()) @@ -340,7 +327,7 @@ ExpEmit FxParameter::Emit(VMFunctionBuilder *build) ExpVal val = Operand->EvalExpression(NULL); if (val.Type == VAL_Int || val.Type == VAL_Sound || val.Type == VAL_Name || val.Type == VAL_Color) { - EmitConstantInt(build, val.Int); + build->EmitParamInt(val.Int); } else if (val.Type == VAL_Float) { @@ -3439,14 +3426,14 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) { assert(argex->ValueType == VAL_Name); assert(argex->isConstant()); - EmitConstantInt(build, -argex->EvalExpression(NULL).GetName()); + build->EmitParamInt(-argex->EvalExpression(NULL).GetName()); } else { assert(argex->ValueType == VAL_Int); if (argex->isConstant()) { - EmitConstantInt(build, argex->EvalExpression(NULL).GetInt()); + build->EmitParamInt(argex->EvalExpression(NULL).GetInt()); } else { @@ -3920,7 +3907,7 @@ ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build) build->Emit(OP_PARAM, 0, REGT_POINTER, 1); // pass stateowner for (unsigned i = 0; i < names.Size(); ++i) { - EmitConstantInt(build, names[i]); + build->EmitParamInt(names[i]); } // For one name, use the DecoFindSingleNameState function. For more than From 9485752b5532965bf6abc540af2bd3abb4b98d27 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 27 Jul 2013 22:00:44 -0500 Subject: [PATCH 102/232] Reimplement MBF code pointer parameters - Where the old code mucked about with parameter lists to convert misc1 and misc2 values to action function parameters, we now create new script functions using a VMFunctionBuilder to pass the parameters to an action function. This code is completely untested, as I have no BEX patches to test it with, but at least it compiles without error. --- src/d_dehacked.cpp | 257 +++++++++++++++++++++++++++------------------ 1 file changed, 157 insertions(+), 100 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 4c826f309..d0ba97237 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -62,8 +62,6 @@ #include "decallib.h" #include "v_palette.h" #include "a_sharedglobal.h" -#include "thingdef/thingdef.h" -#include "thingdef/thingdef_exp.h" #include "vectors.h" #include "dobject.h" #include "r_data/r_translate.h" @@ -72,6 +70,7 @@ #include "doomerrors.h" #include "p_effect.h" #include "farchive.h" +#include "vmbuilder.h" // [SO] Just the way Randy said to do it :) // [RH] Made this CVAR_SERVERINFO @@ -635,26 +634,149 @@ static int GetLine (void) } } -// This enum must be in sync with the Aliases array in DEHSUPP. -enum MBFCodePointers +// misc1 = vrange (arg +3), misc2 = hrange (arg+4) +static int CreateMushroomFunc(VMFunctionBuilder &buildit, int value1, int value2) +{ // A_Mushroom + buildit.Emit(OP_PARAM, 0, REGT_NIL, 0); // spawntype + buildit.Emit(OP_PARAM, 0, REGT_NIL, 0); // numspawns + buildit.Emit(OP_PARAMI, 1); // flag + // vrange + if (value1 == 0) + { + buildit.Emit(OP_PARAM, 0, REGT_NIL, 0); + } + else + { + buildit.Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, buildit.GetConstantFloat(FIXED2DBL(value1))); + } + // hrange + if (value2 == 0) + { + buildit.Emit(OP_PARAM, 0, REGT_NIL, 0); + } + else + { + buildit.Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, buildit.GetConstantFloat(FIXED2DBL(value2))); + } + return 5; +} + +// misc1 = type (arg +0), misc2 = Z-pos (arg +2) +static int CreateSpawnFunc(VMFunctionBuilder &buildit, int value1, int value2) +{ // A_SpawnItem + if (InfoNames[value1-1] == NULL) + { + I_Error("No class found for dehackednum %d!\n", value1+1); + return 0; + } + int typereg = buildit.GetConstantAddress(InfoNames[value1-1], ATAG_OBJECT); + int heightreg = buildit.GetConstantFloat(value2); + + buildit.Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, typereg); // itemtype + buildit.Emit(OP_PARAM, 0, REGT_NIL, 0); // distance + buildit.Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, heightreg); // height + // The rest of the parameters to A_SpawnItem can just keep their defaults + return 3; +} + +// misc1 = angle (in degrees) (arg +0 but factor in current actor angle too) +static int CreateTurnFunc(VMFunctionBuilder &buildit, int value1, int value2) +{ // A_Turn + buildit.Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, buildit.GetConstantFloat(value1)); // angle + return 1; +} + +// misc1 = angle (in degrees) (arg +0) +static int CreateFaceFunc(VMFunctionBuilder &buildit, int value1, int value2) +{ // A_FaceTarget + buildit.Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, buildit.GetConstantFloat(value1)); // angle + return 1; +} + +// misc1 = damage, misc 2 = sound +static int CreateScratchFunc(VMFunctionBuilder &buildit, int value1, int value2) +{ // A_CustomMeleeAttack + buildit.EmitParamInt(value1); // damage + if (value2) + { + buildit.EmitParamInt(SoundMap[value2-1]); // hit sound + return 2; + } + return 1; +} + +// misc1 = sound, misc2 = attenuation none (true) or normal (false) +static int CreatePlaySoundFunc(VMFunctionBuilder &buildit, int value1, int value2) +{ // A_PlaySound + int float1 = buildit.GetConstantFloat(1); + int attenreg = buildit.GetConstantFloat(value2 ? ATTN_NONE : ATTN_NORM); + + buildit.EmitParamInt(SoundMap[value1-1]); // soundid + buildit.Emit(OP_PARAMI, CHAN_BODY); // channel + buildit.Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, float1); // volume + buildit.Emit(OP_PARAMI, false); // looping + buildit.Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, attenreg); // attenuation + return 5; +} + +// misc1 = state, misc2 = probability +static int CreateRandomJumpFunc(VMFunctionBuilder &buildit, int value1, int value2) +{ // A_Jump + int statereg = buildit.GetConstantAddress(FindState(value1), ATAG_STATE); + + buildit.EmitParamInt(value2); // maxchance + buildit.Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, statereg); // jumpto + return 2; +} + +// misc1 = Boom linedef type, misc2 = sector tag +static int CreateLineEffectFunc(VMFunctionBuilder &buildit, int value1, int value2) +{ // A_LineEffect + // This is the second MBF codepointer that couldn't be translated easily. + // Calling P_TranslateLineDef() here was a simple matter, as was adding an + // extra parameter to A_CallSpecial so as to replicate the LINEDONE stuff, + // but unfortunately DEHACKED lumps are processed before the map translation + // arrays are initialized so this didn't work. + buildit.EmitParamInt(value1); // special + buildit.EmitParamInt(value2); // tag + return 2; +} + +// No misc, but it's basically A_Explode with an added effect +static int CreateNailBombFunc(VMFunctionBuilder &buildit, int value1, int value2) +{ // A_Explode + // This one does not actually have MBF-style parameters. But since + // we're aliasing it to an extension of A_Explode... + buildit.Emit(OP_PARAM, 0, REGT_NIL, 0); // damage + buildit.Emit(OP_PARAM, 0, REGT_NIL, 0); // distance + buildit.Emit(OP_PARAM, 0, REGT_NIL, 0); // flags + buildit.Emit(OP_PARAM, 0, REGT_NIL, 0); // alert + buildit.Emit(OP_PARAM, 0, REGT_NIL, 0); // fulldamagedistance + buildit.Emit(OP_PARAMI, 30); // nails + buildit.Emit(OP_PARAMI, 10); // naildamage + return 7; +} + +// This array must be in sync with the Aliases array in DEHSUPP. +static int (*MBFCodePointerFactories[])(VMFunctionBuilder&, int, int) = { // Die and Detonate are not in this list because these codepointers have // no dehacked arguments and therefore do not need special handling. // NailBomb has no argument but is implemented as new parameters for A_Explode. - MBF_Mushroom, // misc1 = vrange (arg +3), misc2 = hrange (arg+4) - MBF_Spawn, // misc1 = type (arg +0), misc2 = Z-pos (arg +2) - MBF_Turn, // misc1 = angle (in degrees) (arg +0 but factor in current actor angle too) - MBF_Face, // misc1 = angle (in degrees) (arg +0) - MBF_Scratch, // misc1 = damage, misc 2 = sound - MBF_PlaySound, // misc1 = sound, misc2 = attenuation none (true) or normal (false) - MBF_RandomJump, // misc1 = state, misc2 = probability - MBF_LineEffect, // misc1 = Boom linedef type, misc2 = sector tag - SMMU_NailBomb, // No misc, but it's basically A_Explode with an added effect + CreateMushroomFunc, + CreateSpawnFunc, + CreateTurnFunc, + CreateFaceFunc, + CreateScratchFunc, + CreatePlaySoundFunc, + CreateRandomJumpFunc, + CreateLineEffectFunc, + CreateNailBombFunc }; -// Hacks the parameter list for the given state so as to convert MBF-args (misc1 and misc2) into real args. +// Creates new functions for the given state so as to convert MBF-args (misc1 and misc2) into real args. -void SetDehParams(FState * state, int codepointer) +void SetDehParams(FState *state, int codepointer) { int value1 = state->GetMisc1(); int value2 = state->GetMisc2(); @@ -663,101 +785,36 @@ void SetDehParams(FState * state, int codepointer) // Fakey fake script position thingamajig. Because NULL cannot be used instead. // Even if the lump was parsed by an FScanner, there would hardly be a way to // identify which line is troublesome. - FScriptPosition * pos = new FScriptPosition(FString("DEHACKED"), 0); + FScriptPosition *pos = new FScriptPosition(FString("DEHACKED"), 0); // Let's identify the codepointer we're dealing with. PSymbolActionFunction *sym; sym = dyn_cast<PSymbolActionFunction>(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(FName(MBFCodePointers[codepointer].name), true)); if (sym == NULL) return; - // Bleargh! This will all have to be redone once scripting works - - // Not sure exactly why the index for a state is greater by one point than the index for a symbol. -#if 0 - DPrintf("SetDehParams: Paramindex is %d, default is %d.\n", - state->ParameterIndex-1, sym->defaultparameterindex); - if (state->ParameterIndex-1 == sym->defaultparameterindex) + if (codepointer < 0 || codepointer >= countof(MBFCodePointerFactories)) { - int a = PrepareStateParameters(state, MBFCodePointers[codepointer].params+1, - FState::StaticFindStateOwner(state)) -1; - int b = sym->defaultparameterindex; - // StateParams.Copy(a, b, MBFParams[codepointer]); - // Meh, function doesn't work. For some reason it resets the paramindex to the default value. - // For instance, a dehacked Commander Keen calling A_Explode would result in a crash as - // ACTION_PARAM_INT(damage, 0) would properly evaluate at paramindex 1377, but then - // ACTION_PARAM_INT(distance, 1) would improperly evaluate at paramindex 148! Now I'm not sure - // whether it's a genuine problem or working as intended and merely not appropriate for the - // task at hand here. So rather than modify it, I use a simple for loop of Set()s and Get()s, - // with a small modification to Set() that I know will have no repercussion anywhere else. - for (int i = 0; i<MBFCodePointers[codepointer].params; i++) - { - StateParams.Set(a+i, StateParams.Get(b+i), true); - } - DPrintf("New paramindex is %d.\n", state->ParameterIndex-1); - } - int ParamIndex = state->ParameterIndex - 1; - - switch (codepointer) - { - case MBF_Mushroom: - StateParams.Set(ParamIndex+2, new FxConstant(1, *pos)); // Flag - // NOTE: Do not convert to float here because it will lose precision. It must be double. - if (value1) StateParams.Set(ParamIndex+3, new FxConstant(value1/65536., *pos)); // vrange - if (value2) StateParams.Set(ParamIndex+4, new FxConstant(value2/65536., *pos)); // hrange - break; - case MBF_Spawn: - if (InfoNames[value1-1] == NULL) - { - I_Error("No class found for dehackednum %d!\n", value1+1); - return; - } - StateParams.Set(ParamIndex+0, new FxConstant(InfoNames[value1-1], *pos)); // type - StateParams.Set(ParamIndex+2, new FxConstant(value2, *pos)); // height - break; - case MBF_Turn: - // Intentional fall through. I tried something more complicated by creating an - // FxExpression that corresponded to "variable angle + angle" so as to use A_SetAngle - // as well, but it became an overcomplicated mess that didn't even work as I had to - // create a compile context as well and couldn't get it right. - case MBF_Face: - StateParams.Set(ParamIndex+0, new FxConstant(value1, *pos)); // angle - break; - case MBF_Scratch: // misc1 = damage, misc 2 = sound - StateParams.Set(ParamIndex+0, new FxConstant(value1, *pos)); // damage - if (value2) StateParams.Set(ParamIndex+1, new FxConstant(SoundMap[value2-1], *pos)); // hit sound - break; - case MBF_PlaySound: - StateParams.Set(ParamIndex+0, new FxConstant(SoundMap[value1-1], *pos)); // soundid - StateParams.Set(ParamIndex+1, new FxConstant(CHAN_BODY, *pos)); // channel - StateParams.Set(ParamIndex+2, new FxConstant(1.0, *pos)); // volume - StateParams.Set(ParamIndex+3, new FxConstant(false, *pos)); // looping - StateParams.Set(ParamIndex+4, new FxConstant((value2 ? ATTN_NONE : ATTN_NORM), *pos)); // attenuation - break; - case MBF_RandomJump: - StateParams.Set(ParamIndex+0, new FxConstant(2, *pos)); // count - StateParams.Set(ParamIndex+1, new FxConstant(value2, *pos)); // maxchance - StateParams.Set(ParamIndex+2, new FxConstant(FindState(value1), *pos)); // jumpto - break; - case MBF_LineEffect: - // This is the second MBF codepointer that couldn't be translated easily. - // Calling P_TranslateLineDef() here was a simple matter, as was adding an - // extra parameter to A_CallSpecial so as to replicate the LINEDONE stuff, - // but unfortunately DEHACKED lumps are processed before the map translation - // arrays are initialized so this didn't work. - StateParams.Set(ParamIndex+0, new FxConstant(value1, *pos)); // special - StateParams.Set(ParamIndex+1, new FxConstant(value2, *pos)); // tag - break; - case SMMU_NailBomb: - // That one does not actually have MBF-style parameters. But since - // we're aliasing it to an extension of A_Explode... - StateParams.Set(ParamIndex+5, new FxConstant(30, *pos)); // nails - StateParams.Set(ParamIndex+6, new FxConstant(10, *pos)); // naildamage - break; - default: // This simply should not happen. Printf("Unmanaged dehacked codepointer alias num %i\n", codepointer); } -#endif + else + { + VMFunctionBuilder buildit; + // Allocate registers used to pass parameters in. + // self, stateowner, state (all are pointers) + buildit.Registers[REGT_POINTER].Get(3); + // Emit code to pass the standard action function parameters. + buildit.Emit(OP_PARAM, 0, REGT_POINTER, 0); + buildit.Emit(OP_PARAM, 0, REGT_POINTER, 1); + buildit.Emit(OP_PARAM, 0, REGT_POINTER, 2); + // Emit code for action parameters. + int argcount = MBFCodePointerFactories[codepointer](buildit, value1, value2); + buildit.Emit(OP_TAIL_K, buildit.GetConstantAddress(sym->Function, ATAG_OBJECT), NAP + argcount, 0); + // Attach it to the state. + VMScriptFunction *sfunc = buildit.MakeFunction(); + sfunc->NumArgs = NAP; + state->SetAction(sfunc); + } } static int PatchThing (int thingy) From 4a1fbdb32a4e109efc4840890c2676d5b76e2912 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 27 Jul 2013 22:34:44 -0500 Subject: [PATCH 103/232] Remove all state expression/param stuff - This all became vestigial code after the relevant information was all moved into FStateTempCall. Now that the MBF code pointer code has been converted, I can be sure it wasn't still used anywhere. --- src/dobjtype.h | 1 - src/thingdef/thingdef.cpp | 3 +- src/thingdef/thingdef.h | 27 ------ src/thingdef/thingdef_expression.cpp | 130 --------------------------- src/thingdef/thingdef_parse.cpp | 12 --- src/thingdef/thingdef_states.cpp | 15 ---- 6 files changed, 1 insertion(+), 187 deletions(-) diff --git a/src/dobjtype.h b/src/dobjtype.h index b04f7fce5..b245611bc 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -87,7 +87,6 @@ class PSymbolActionFunction : public PSymbol public: FString Arguments; VMFunction *Function; - int defaultparameterindex; PSymbolActionFunction(FName name) : PSymbol(name) {} PSymbolActionFunction() : PSymbol(NAME_None) {} diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 36c09d716..ef0be1d23 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -276,7 +276,7 @@ static void DumpFunction(FILE *dump, VMScriptFunction *sfunc, const char *label, static void FinishThingdef() { - int errorcount = StateParams.ResolveAll(); + int errorcount = 0; unsigned i, j; int codesize = 0; @@ -419,7 +419,6 @@ void LoadActors () cycle_t timer; timer.Reset(); timer.Clock(); - StateParams.Clear(); ActorDamageFuncs.Clear(); GlobalSymbols.ReleaseSymbols(); FScriptPosition::ResetErrorCounter(); diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index b65bb4637..1b253ec89 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -127,33 +127,6 @@ struct FStateTempCall int NumStates; }; extern TDeletingArray<FStateTempCall *> StateTempCalls; - -struct FStateExpression -{ - FxExpression *expr; - PClassActor *owner; - bool constant; - bool cloned; -}; - -class FStateExpressions -{ - TArray<FStateExpression> expressions; - -public: - ~FStateExpressions() { Clear(); } - void Clear(); - int Add(FxExpression *x, PClassActor *o, bool c); - int Reserve(int num, PClassActor *cls); -// void Set(int num, FxExpression *x, bool cloned = false); -// void Copy(int dest, int src, int cnt); - int ResolveAll(); - FxExpression *Get(int no); - unsigned int Size() { return expressions.Size(); } -}; - -extern FStateExpressions StateParams; - extern TDeletingArray<class FxExpression *> ActorDamageFuncs; //========================================================================== diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index bd2dfe70e..5541972df 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3990,133 +3990,3 @@ ExpEmit FxDamageValue::Emit(VMFunctionBuilder *build) return ExpEmit(); } - - -//========================================================================== -// -// NOTE: I don't expect any of the following to survive Doomscript ;) -// -//========================================================================== - -FStateExpressions StateParams; - - -//========================================================================== -// -// -// -//========================================================================== - -void FStateExpressions::Clear() -{ - for(unsigned i=0; i<Size(); i++) - { - if (expressions[i].expr != NULL && !expressions[i].cloned) - { - delete expressions[i].expr; - } - } - expressions.Clear(); -} - -//========================================================================== -// -// -// -//========================================================================== - -int FStateExpressions::Add(FxExpression *x, PClassActor *o, bool c) -{ - int idx = expressions.Reserve(1); - FStateExpression &exp = expressions[idx]; - exp.expr = x; - exp.owner = o; - exp.constant = c; - exp.cloned = false; - return idx; -} - -//========================================================================== -// -// -// -//========================================================================== - -int FStateExpressions::Reserve(int num, PClassActor *cls) -{ - int idx = expressions.Reserve(num); - FStateExpression *exp = &expressions[idx]; - for(int i = 0; i < num; i++) - { - exp[i].expr = NULL; - exp[i].owner = cls; - exp[i].constant = false; - exp[i].cloned = false; - } - return idx; -} - -//========================================================================== -// -// -// -//========================================================================== - -int FStateExpressions::ResolveAll() -{ - int errorcount = 0; - - FCompileContext ctx; - ctx.lax = true; - for(unsigned i=0; i<Size(); i++) - { - if (expressions[i].cloned) - { - // Now that everything coming before has been resolved we may copy the actual pointer. - unsigned ii = unsigned((intptr_t)expressions[i].expr); - expressions[i].expr = expressions[ii].expr; - } - else if (expressions[i].expr != NULL) - { - ctx.cls = expressions[i].owner; - ctx.isconst = expressions[i].constant; - expressions[i].expr = expressions[i].expr->Resolve(ctx); - if (expressions[i].expr == NULL) - { - errorcount++; - } - else if (expressions[i].constant && !expressions[i].expr->isConstant()) - { - expressions[i].expr->ScriptPosition.Message(MSG_ERROR, "Constant expression expected"); - errorcount++; - } - } - } - - for(unsigned i=0; i<Size(); i++) - { - if (expressions[i].expr != NULL) - { - if (!expressions[i].expr->isresolved) - { - expressions[i].expr->ScriptPosition.Message(MSG_ERROR, "Expression at index %d not resolved\n", i); - errorcount++; - } - } - } - - return errorcount; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FStateExpressions::Get(int num) -{ - if (num >= 0 && num < int(Size())) - return expressions[num].expr; - return NULL; -} diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index d07f481a1..f7f310c2b 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -1010,18 +1010,6 @@ static void ParseActionDef (FScanner &sc, PClassActor *cls) PSymbolActionFunction *sym = new PSymbolActionFunction(funcname); sym->Arguments = args; sym->Function = *(afd->VMPointer); - if (hasdefaults) - { - sym->defaultparameterindex = StateParams.Size(); - for(unsigned int i = 0; i < DefaultParams.Size(); i++) - { - StateParams.Add(DefaultParams[i], cls, true); - } - } - else - { - sym->defaultparameterindex = -1; - } if (error) { FScriptPosition::ErrorCounter++; diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index 9bd3a562a..fb3ecf673 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -331,25 +331,13 @@ do_stop: { if (!sc.CheckString("(")) { -// state.ParameterIndex = afd->defaultparameterindex+1; goto endofstate; } } -// int paramindex = PrepareStateParameters(&state, numparams, bag.Info->Class); -// int paramstart = paramindex; bool varargs = params[numparams - 1] == '+'; int varargcount = 0; - if (varargs) - { -// paramindex++; - } - else if (afd->defaultparameterindex > -1) - { -// StateParams.Copy(paramindex, afd->defaultparameterindex, int(afd->Arguments.Len())); - } - while (*params) { FxExpression *x; @@ -381,7 +369,6 @@ do_stop: // Use the generic parameter parser for everything else x = ParseParameter(sc, bag.Info, *params, false); } -// StateParams.Set(paramindex++, x); tcall->Parameters.Push(new FxParameter(x)); params++; varargcount++; @@ -391,11 +378,9 @@ do_stop: { if (sc.CheckString(")")) { -// StateParams.Set(paramstart, new FxConstant(argcount, sc)); goto endofstate; } params--; - StateParams.Reserve(1, bag.Info); } else if ((islower(*params) || *params=='!') && sc.CheckString(")")) { From 2c24e7f9c6039bc315aad4ffa662d7df6dc1070a Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sun, 28 Jul 2013 19:28:14 -0500 Subject: [PATCH 104/232] Remove self pointer from FxExpression::EvalExpression() - Every place that calls this now (which are all in thingdef_parse.cpp) passed NULL for the self pointer, so it was superfluous to have around. --- src/thingdef/thingdef_exp.h | 52 +++---- src/thingdef/thingdef_expression.cpp | 223 +++++++++++++-------------- src/thingdef/thingdef_parse.cpp | 10 +- 3 files changed, 140 insertions(+), 145 deletions(-) diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index abca3c722..c88260ac0 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -230,7 +230,7 @@ public: virtual FxExpression *Resolve(FCompileContext &ctx); FxExpression *ResolveAsBoolean(FCompileContext &ctx); - virtual ExpVal EvalExpression (AActor *self); + virtual ExpVal EvalExpression(); virtual bool isConstant() const; virtual void RequestAddress(); @@ -377,7 +377,7 @@ public: { return true; } - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -398,7 +398,7 @@ public: ~FxIntCast(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -412,7 +412,7 @@ public: ~FxFloatCast(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -448,7 +448,7 @@ public: FxMinusSign(FxExpression*); ~FxMinusSign(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -466,7 +466,7 @@ public: FxUnaryNotBitwise(FxExpression*); ~FxUnaryNotBitwise(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -484,7 +484,7 @@ public: FxUnaryNotBoolean(FxExpression*); ~FxUnaryNotBoolean(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -519,7 +519,7 @@ public: FxAddSub(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -535,7 +535,7 @@ public: FxMulDiv(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -551,7 +551,7 @@ public: FxCompareRel(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -567,7 +567,7 @@ public: FxCompareEq(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -583,7 +583,7 @@ public: FxBinaryInt(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -604,7 +604,7 @@ public: ~FxBinaryLogical(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -625,7 +625,7 @@ public: ~FxConditional(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -645,7 +645,7 @@ public: ~FxAbs(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -667,7 +667,7 @@ public: ~FxRandom(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -681,7 +681,7 @@ class FxFRandom : public FxRandom { public: FxFRandom(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos); - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -702,7 +702,7 @@ public: ~FxRandom2(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -722,7 +722,7 @@ public: FxGlobalVariable(PSymbolVariable*, const FScriptPosition&); FxExpression *Resolve(FCompileContext&); void RequestAddress(); - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); }; //========================================================================== @@ -742,7 +742,7 @@ public: ~FxClassMember(); FxExpression *Resolve(FCompileContext&); void RequestAddress(); - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -757,7 +757,7 @@ class FxSelf : public FxExpression public: FxSelf(const FScriptPosition&); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -778,7 +778,7 @@ public: ~FxArrayElement(); FxExpression *Resolve(FCompileContext&); //void RequestAddress(); - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -822,7 +822,7 @@ public: FxActionSpecialCall(FxExpression *self, int special, FArgumentList *args, const FScriptPosition &pos); ~FxActionSpecialCall(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -842,7 +842,7 @@ public: FxGlobalFunctionCall(FName fname, FArgumentList *args, const FScriptPosition &pos); ~FxGlobalFunctionCall(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -863,7 +863,7 @@ public: FxClassTypeCast(const PClass *dtype, FxExpression *x); ~FxClassTypeCast(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -900,7 +900,7 @@ public: FxMultiNameState(const char *statestring, const FScriptPosition &pos); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 5541972df..7946cfc07 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -198,7 +198,7 @@ static ExpVal GetVariableValue (void *address, FExpressionType &type) // //========================================================================== -ExpVal FxExpression::EvalExpression (AActor *self) +ExpVal FxExpression::EvalExpression() { ScriptPosition.Message(MSG_ERROR, "Unresolved expression found"); ExpVal val; @@ -324,7 +324,7 @@ ExpEmit FxParameter::Emit(VMFunctionBuilder *build) { if (Operand->isConstant()) { - ExpVal val = Operand->EvalExpression(NULL); + ExpVal val = Operand->EvalExpression(); if (val.Type == VAL_Int || val.Type == VAL_Sound || val.Type == VAL_Name || val.Type == VAL_Color) { build->EmitParamInt(val.Int); @@ -375,7 +375,7 @@ ExpEmit FxParameter::Emit(VMFunctionBuilder *build) // //========================================================================== -ExpVal FxConstant::EvalExpression (AActor *self) +ExpVal FxConstant::EvalExpression() { return value; } @@ -500,7 +500,7 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx) { if (basex->isConstant()) { - ExpVal constval = basex->EvalExpression(NULL); + ExpVal constval = basex->EvalExpression(); FxExpression *x = new FxConstant(constval.GetInt(), ScriptPosition); delete this; return x; @@ -521,9 +521,9 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxIntCast::EvalExpression (AActor *self) +ExpVal FxIntCast::EvalExpression() { - ExpVal baseval = basex->EvalExpression(self); + ExpVal baseval = basex->EvalExpression(); baseval.Int = baseval.GetInt(); baseval.Type = VAL_Int; return baseval; @@ -585,7 +585,7 @@ FxExpression *FxFloatCast::Resolve(FCompileContext &ctx) { if (basex->isConstant()) { - ExpVal constval = basex->EvalExpression(NULL); + ExpVal constval = basex->EvalExpression(); FxExpression *x = new FxConstant(constval.GetFloat(), ScriptPosition); delete this; return x; @@ -606,9 +606,9 @@ FxExpression *FxFloatCast::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxFloatCast::EvalExpression (AActor *self) +ExpVal FxFloatCast::EvalExpression() { - ExpVal baseval = basex->EvalExpression(self); + ExpVal baseval = basex->EvalExpression(); baseval.Float = baseval.GetFloat(); baseval.Type = VAL_Float; return baseval; @@ -717,7 +717,7 @@ FxExpression *FxMinusSign::Resolve(FCompileContext& ctx) { if (Operand->isConstant()) { - ExpVal val = Operand->EvalExpression(NULL); + ExpVal val = Operand->EvalExpression(); FxExpression *e = val.Type == VAL_Int? new FxConstant(-val.Int, ScriptPosition) : new FxConstant(-val.Float, ScriptPosition); @@ -741,18 +741,18 @@ FxExpression *FxMinusSign::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxMinusSign::EvalExpression (AActor *self) +ExpVal FxMinusSign::EvalExpression() { ExpVal ret; if (ValueType == VAL_Int) { - ret.Int = -Operand->EvalExpression(self).GetInt(); + ret.Int = -Operand->EvalExpression().GetInt(); ret.Type = VAL_Int; } else { - ret.Float = -Operand->EvalExpression(self).GetFloat(); + ret.Float = -Operand->EvalExpression().GetFloat(); ret.Type = VAL_Float; } return ret; @@ -831,7 +831,7 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx) if (Operand->isConstant()) { - int result = ~Operand->EvalExpression(NULL).GetInt(); + int result = ~Operand->EvalExpression().GetInt(); FxExpression *e = new FxConstant(result, ScriptPosition); delete this; return e; @@ -846,11 +846,11 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxUnaryNotBitwise::EvalExpression (AActor *self) +ExpVal FxUnaryNotBitwise::EvalExpression() { ExpVal ret; - ret.Int = ~Operand->EvalExpression(self).GetInt(); + ret.Int = ~Operand->EvalExpression().GetInt(); ret.Type = VAL_Int; return ret; } @@ -913,7 +913,7 @@ FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx) { if (Operand->isConstant()) { - bool result = !Operand->EvalExpression(NULL).GetBool(); + bool result = !Operand->EvalExpression().GetBool(); FxExpression *e = new FxConstant(result, ScriptPosition); delete this; return e; @@ -935,11 +935,11 @@ FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxUnaryNotBoolean::EvalExpression (AActor *self) +ExpVal FxUnaryNotBoolean::EvalExpression() { ExpVal ret; - ret.Int = !Operand->EvalExpression(self).GetBool(); + ret.Int = !Operand->EvalExpression().GetBool(); ret.Type = VAL_Int; return ret; } @@ -1089,8 +1089,8 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx) if (ValueType == VAL_Float) { double v; - double v1 = left->EvalExpression(NULL).GetFloat(); - double v2 = right->EvalExpression(NULL).GetFloat(); + double v1 = left->EvalExpression().GetFloat(); + double v2 = right->EvalExpression().GetFloat(); v = Operator == '+'? v1 + v2 : Operator == '-'? v1 - v2 : 0; @@ -1102,8 +1102,8 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx) else { int v; - int v1 = left->EvalExpression(NULL).GetInt(); - int v2 = right->EvalExpression(NULL).GetInt(); + int v1 = left->EvalExpression().GetInt(); + int v2 = right->EvalExpression().GetInt(); v = Operator == '+'? v1 + v2 : Operator == '-'? v1 - v2 : 0; @@ -1124,14 +1124,14 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxAddSub::EvalExpression (AActor *self) +ExpVal FxAddSub::EvalExpression() { ExpVal ret; if (ValueType == VAL_Float) { - double v1 = left->EvalExpression(self).GetFloat(); - double v2 = right->EvalExpression(self).GetFloat(); + double v1 = left->EvalExpression().GetFloat(); + double v2 = right->EvalExpression().GetFloat(); ret.Type = VAL_Float; ret.Float = Operator == '+'? v1 + v2 : @@ -1139,8 +1139,8 @@ ExpVal FxAddSub::EvalExpression (AActor *self) } else { - int v1 = left->EvalExpression(self).GetInt(); - int v2 = right->EvalExpression(self).GetInt(); + int v1 = left->EvalExpression().GetInt(); + int v2 = right->EvalExpression().GetInt(); ret.Type = VAL_Int; ret.Int = Operator == '+'? v1 + v2 : @@ -1241,8 +1241,8 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) if (ValueType == VAL_Float) { double v; - double v1 = left->EvalExpression(NULL).GetFloat(); - double v2 = right->EvalExpression(NULL).GetFloat(); + double v1 = left->EvalExpression().GetFloat(); + double v2 = right->EvalExpression().GetFloat(); if (Operator != '*' && v2 == 0) { @@ -1262,8 +1262,8 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) else { int v; - int v1 = left->EvalExpression(NULL).GetInt(); - int v2 = right->EvalExpression(NULL).GetInt(); + int v1 = left->EvalExpression().GetInt(); + int v2 = right->EvalExpression().GetInt(); if (Operator != '*' && v2 == 0) { @@ -1293,14 +1293,14 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxMulDiv::EvalExpression (AActor *self) +ExpVal FxMulDiv::EvalExpression() { ExpVal ret; if (ValueType == VAL_Float) { - double v1 = left->EvalExpression(self).GetFloat(); - double v2 = right->EvalExpression(self).GetFloat(); + double v1 = left->EvalExpression().GetFloat(); + double v2 = right->EvalExpression().GetFloat(); if (Operator != '*' && v2 == 0) { @@ -1314,8 +1314,8 @@ ExpVal FxMulDiv::EvalExpression (AActor *self) } else { - int v1 = left->EvalExpression(self).GetInt(); - int v2 = right->EvalExpression(self).GetInt(); + int v1 = left->EvalExpression().GetInt(); + int v2 = right->EvalExpression().GetInt(); if (Operator != '*' && v2 == 0) { @@ -1425,8 +1425,8 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) if (ValueType == VAL_Float) { - double v1 = left->EvalExpression(NULL).GetFloat(); - double v2 = right->EvalExpression(NULL).GetFloat(); + double v1 = left->EvalExpression().GetFloat(); + double v2 = right->EvalExpression().GetFloat(); v = Operator == '<'? v1 < v2 : Operator == '>'? v1 > v2 : Operator == TK_Geq? v1 >= v2 : @@ -1434,8 +1434,8 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) } else { - int v1 = left->EvalExpression(NULL).GetInt(); - int v2 = right->EvalExpression(NULL).GetInt(); + int v1 = left->EvalExpression().GetInt(); + int v2 = right->EvalExpression().GetInt(); v = Operator == '<'? v1 < v2 : Operator == '>'? v1 > v2 : Operator == TK_Geq? v1 >= v2 : @@ -1457,7 +1457,7 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxCompareRel::EvalExpression (AActor *self) +ExpVal FxCompareRel::EvalExpression() { ExpVal ret; @@ -1465,8 +1465,8 @@ ExpVal FxCompareRel::EvalExpression (AActor *self) if (left->ValueType == VAL_Float || right->ValueType == VAL_Float) { - double v1 = left->EvalExpression(self).GetFloat(); - double v2 = right->EvalExpression(self).GetFloat(); + double v1 = left->EvalExpression().GetFloat(); + double v2 = right->EvalExpression().GetFloat(); ret.Int = Operator == '<'? v1 < v2 : Operator == '>'? v1 > v2 : Operator == TK_Geq? v1 >= v2 : @@ -1474,8 +1474,8 @@ ExpVal FxCompareRel::EvalExpression (AActor *self) } else { - int v1 = left->EvalExpression(self).GetInt(); - int v2 = right->EvalExpression(self).GetInt(); + int v1 = left->EvalExpression().GetInt(); + int v2 = right->EvalExpression().GetInt(); ret.Int = Operator == '<'? v1 < v2 : Operator == '>'? v1 > v2 : Operator == TK_Geq? v1 >= v2 : @@ -1584,14 +1584,14 @@ cont: if (ValueType == VAL_Float) { - double v1 = left->EvalExpression(NULL).GetFloat(); - double v2 = right->EvalExpression(NULL).GetFloat(); + double v1 = left->EvalExpression().GetFloat(); + double v2 = right->EvalExpression().GetFloat(); v = Operator == TK_Eq? v1 == v2 : v1 != v2; } else { - int v1 = left->EvalExpression(NULL).GetInt(); - int v2 = right->EvalExpression(NULL).GetInt(); + int v1 = left->EvalExpression().GetInt(); + int v2 = right->EvalExpression().GetInt(); v = Operator == TK_Eq? v1 == v2 : v1 != v2; } FxExpression *e = new FxConstant(v, ScriptPosition); @@ -1609,7 +1609,7 @@ cont: // //========================================================================== -ExpVal FxCompareEq::EvalExpression (AActor *self) +ExpVal FxCompareEq::EvalExpression() { ExpVal ret; @@ -1617,14 +1617,14 @@ ExpVal FxCompareEq::EvalExpression (AActor *self) if (left->ValueType == VAL_Float || right->ValueType == VAL_Float) { - double v1 = left->EvalExpression(self).GetFloat(); - double v2 = right->EvalExpression(self).GetFloat(); + double v1 = left->EvalExpression().GetFloat(); + double v2 = right->EvalExpression().GetFloat(); ret.Int = Operator == TK_Eq? v1 == v2 : v1 != v2; } else if (left->ValueType == VAL_Int) { - int v1 = left->EvalExpression(self).GetInt(); - int v2 = right->EvalExpression(self).GetInt(); + int v1 = left->EvalExpression().GetInt(); + int v2 = right->EvalExpression().GetInt(); ret.Int = Operator == TK_Eq? v1 == v2 : v1 != v2; } else @@ -1725,8 +1725,8 @@ FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx) } else if (left->isConstant() && right->isConstant()) { - int v1 = left->EvalExpression(NULL).GetInt(); - int v2 = right->EvalExpression(NULL).GetInt(); + int v1 = left->EvalExpression().GetInt(); + int v2 = right->EvalExpression().GetInt(); FxExpression *e = new FxConstant( Operator == TK_LShift? v1 << v2 : @@ -1748,10 +1748,10 @@ FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxBinaryInt::EvalExpression (AActor *self) +ExpVal FxBinaryInt::EvalExpression() { - int v1 = left->EvalExpression(self).GetInt(); - int v2 = right->EvalExpression(self).GetInt(); + int v1 = left->EvalExpression().GetInt(); + int v2 = right->EvalExpression().GetInt(); ExpVal ret; @@ -1795,7 +1795,7 @@ ExpEmit FxBinaryInt::Emit(VMFunctionBuilder *build) { // Shift instructions use right-hand immediates instead of constant registers. if (right->isConstant()) { - rop = right->EvalExpression(NULL).GetInt(); + rop = right->EvalExpression().GetInt(); op2.Konst = true; } else @@ -1886,8 +1886,8 @@ FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx) int b_left=-1, b_right=-1; - if (left->isConstant()) b_left = left->EvalExpression(NULL).GetBool(); - if (right->isConstant()) b_right = right->EvalExpression(NULL).GetBool(); + if (left->isConstant()) b_left = left->EvalExpression().GetBool(); + if (right->isConstant()) b_right = right->EvalExpression().GetBool(); // Do some optimizations. This will throw out all sub-expressions that are not // needed to retrieve the final result. @@ -1966,9 +1966,9 @@ FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxBinaryLogical::EvalExpression (AActor *self) +ExpVal FxBinaryLogical::EvalExpression() { - bool b_left = left->EvalExpression(self).GetBool(); + bool b_left = left->EvalExpression().GetBool(); ExpVal ret; ret.Type = VAL_Int; @@ -1976,11 +1976,11 @@ ExpVal FxBinaryLogical::EvalExpression (AActor *self) if (Operator == TK_AndAnd) { - ret.Int = (b_left && right->EvalExpression(self).GetBool()); + ret.Int = (b_left && right->EvalExpression().GetBool()); } else if (Operator == TK_OrOr) { - ret.Int = (b_left || right->EvalExpression(self).GetBool()); + ret.Int = (b_left || right->EvalExpression().GetBool()); } return ret; } @@ -2088,7 +2088,7 @@ FxExpression *FxConditional::Resolve(FCompileContext& ctx) if (condition->isConstant()) { - ExpVal condval = condition->EvalExpression(NULL); + ExpVal condval = condition->EvalExpression(); bool result = condval.GetBool(); FxExpression *e = result? truex:falsex; @@ -2121,13 +2121,13 @@ FxExpression *FxConditional::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxConditional::EvalExpression (AActor *self) +ExpVal FxConditional::EvalExpression() { - ExpVal condval = condition->EvalExpression(self); + ExpVal condval = condition->EvalExpression(); bool result = condval.GetBool(); FxExpression *e = result? truex:falsex; - return e->EvalExpression(self); + return e->EvalExpression(); } ExpEmit FxConditional::Emit(VMFunctionBuilder *build) @@ -2148,7 +2148,7 @@ ExpEmit FxConditional::Emit(VMFunctionBuilder *build) if (truex->isConstant() && truex->ValueType == VAL_Int) { out = ExpEmit(build, REGT_INT); - build->EmitLoadInt(out.RegNum, truex->EvalExpression(NULL).GetInt()); + build->EmitLoadInt(out.RegNum, truex->EvalExpression().GetInt()); } else { @@ -2171,7 +2171,7 @@ ExpEmit FxConditional::Emit(VMFunctionBuilder *build) build->BackpatchToHere(patchspot); if (falsex->isConstant() && falsex->ValueType == VAL_Int) { - build->EmitLoadInt(out.RegNum, falsex->EvalExpression(NULL).GetInt()); + build->EmitLoadInt(out.RegNum, falsex->EvalExpression().GetInt()); } else { @@ -2245,7 +2245,7 @@ FxExpression *FxAbs::Resolve(FCompileContext &ctx) } else if (val->isConstant()) { - ExpVal value = val->EvalExpression(NULL); + ExpVal value = val->EvalExpression(); switch (value.Type) { case VAL_Int: @@ -2274,9 +2274,9 @@ FxExpression *FxAbs::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxAbs::EvalExpression (AActor *self) +ExpVal FxAbs::EvalExpression() { - ExpVal value = val->EvalExpression(self); + ExpVal value = val->EvalExpression(); switch (value.Type) { default: @@ -2365,15 +2365,15 @@ FxExpression *FxRandom::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxRandom::EvalExpression (AActor *self) +ExpVal FxRandom::EvalExpression() { ExpVal val; val.Type = VAL_Int; if (min != NULL && max != NULL) { - int minval = min->EvalExpression (self).GetInt(); - int maxval = max->EvalExpression (self).GetInt(); + int minval = min->EvalExpression().GetInt(); + int maxval = max->EvalExpression().GetInt(); if (maxval < minval) { @@ -2462,7 +2462,7 @@ FxFRandom::FxFRandom(FRandom *r, FxExpression *mi, FxExpression *ma, const FScri // //========================================================================== -ExpVal FxFRandom::EvalExpression (AActor *self) +ExpVal FxFRandom::EvalExpression() { ExpVal val; val.Type = VAL_Float; @@ -2471,8 +2471,8 @@ ExpVal FxFRandom::EvalExpression (AActor *self) if (min != NULL && max != NULL) { - double minval = min->EvalExpression (self).GetFloat(); - double maxval = max->EvalExpression (self).GetFloat(); + double minval = min->EvalExpression().GetFloat(); + double maxval = max->EvalExpression().GetFloat(); if (maxval < minval) { @@ -2584,9 +2584,9 @@ FxExpression *FxRandom2::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxRandom2::EvalExpression (AActor *self) +ExpVal FxRandom2::EvalExpression() { - ExpVal maskval = mask->EvalExpression(self); + ExpVal maskval = mask->EvalExpression(); int imaskval = maskval.GetInt(); maskval.Type = VAL_Int; @@ -2749,12 +2749,12 @@ FxExpression *FxSelf::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxSelf::EvalExpression (AActor *self) +ExpVal FxSelf::EvalExpression() { ExpVal ret; ret.Type = VAL_Object; - ret.pointer = self; + ret.pointer = NULL; return ret; } @@ -2830,7 +2830,7 @@ FxExpression *FxGlobalVariable::Resolve(FCompileContext&) // //========================================================================== -ExpVal FxGlobalVariable::EvalExpression (AActor *self) +ExpVal FxGlobalVariable::EvalExpression() { ExpVal ret; @@ -2933,7 +2933,7 @@ FxExpression *FxClassMember::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxClassMember::EvalExpression (AActor *self) +ExpVal FxClassMember::EvalExpression() { char *object = NULL; if (classx->ValueType == VAL_Class) @@ -2942,7 +2942,7 @@ ExpVal FxClassMember::EvalExpression (AActor *self) } else { - object = classx->EvalExpression(self).GetPointer<char>(); + object = classx->EvalExpression().GetPointer<char>(); } if (object == NULL) { @@ -3140,10 +3140,10 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxArrayElement::EvalExpression (AActor *self) +ExpVal FxArrayElement::EvalExpression() { - int * arraystart = Array->EvalExpression(self).GetPointer<int>(); - int indexval = index->EvalExpression(self).GetInt(); + int * arraystart = Array->EvalExpression().GetPointer<int>(); + int indexval = index->EvalExpression().GetInt(); if (indexval < 0 || indexval >= Array->ValueType.size) { @@ -3169,7 +3169,7 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) } if (index->isConstant()) { - int indexval = index->EvalExpression(NULL).GetInt(); + int indexval = index->EvalExpression().GetInt(); if (indexval < 0 || indexval >= Array->ValueType.size) { I_Error("Array index out of bounds"); @@ -3363,16 +3363,11 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxActionSpecialCall::EvalExpression (AActor *self) +ExpVal FxActionSpecialCall::EvalExpression() { int v[5] = {0,0,0,0,0}; int special = Special; - if (Self != NULL) - { - self = Self->EvalExpression(self).GetPointer<AActor>(); - } - if (ArgList != NULL) { for(unsigned i = 0; i < ArgList->Size(); i++) @@ -3380,17 +3375,17 @@ ExpVal FxActionSpecialCall::EvalExpression (AActor *self) if (special < 0) { special = -special; - v[i] = -(*ArgList)[i]->EvalExpression(self).GetName(); + v[i] = -(*ArgList)[i]->EvalExpression().GetName(); } else { - v[i] = (*ArgList)[i]->EvalExpression(self).GetInt(); + v[i] = (*ArgList)[i]->EvalExpression().GetInt(); } } } ExpVal ret; ret.Type = VAL_Int; - ret.Int = P_ExecuteSpecial(special, NULL, self, false, v[0], v[1], v[2], v[3], v[4]); + ret.Int = P_ExecuteSpecial(special, NULL, NULL, false, v[0], v[1], v[2], v[3], v[4]); return ret; } @@ -3426,14 +3421,14 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) { assert(argex->ValueType == VAL_Name); assert(argex->isConstant()); - build->EmitParamInt(-argex->EvalExpression(NULL).GetName()); + build->EmitParamInt(-argex->EvalExpression().GetName()); } else { assert(argex->ValueType == VAL_Int); if (argex->isConstant()) { - build->EmitParamInt(argex->EvalExpression(NULL).GetInt()); + build->EmitParamInt(argex->EvalExpression().GetInt()); } else { @@ -3508,7 +3503,7 @@ FxExpression *FxGlobalFunctionCall::Resolve(FCompileContext& ctx) } if ((*ArgList)[0]->isConstant()) { - double v = (*ArgList)[0]->EvalExpression(NULL).GetFloat(); + double v = (*ArgList)[0]->EvalExpression().GetFloat(); if (Name == NAME_Sqrt) { v = sqrt(v); @@ -3535,9 +3530,9 @@ FxExpression *FxGlobalFunctionCall::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxGlobalFunctionCall::EvalExpression (AActor *self) +ExpVal FxGlobalFunctionCall::EvalExpression() { - double v = (*ArgList)[0]->EvalExpression(self).GetFloat(); + double v = (*ArgList)[0]->EvalExpression().GetFloat(); ExpVal ret; ret.Type = VAL_Float; @@ -3608,7 +3603,7 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) if (basex->isConstant()) { - FName clsname = basex->EvalExpression(NULL).GetName(); + FName clsname = basex->EvalExpression().GetName(); const PClass *cls = NULL; if (clsname != NAME_None) @@ -3651,9 +3646,9 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxClassTypeCast::EvalExpression (AActor *self) +ExpVal FxClassTypeCast::EvalExpression() { - FName clsname = basex->EvalExpression(NULL).GetName(); + FName clsname = basex->EvalExpression().GetName(); const PClass *cls = PClass::FindClass(clsname); if (!cls->IsDescendantOf(desttype)) @@ -3836,11 +3831,11 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxMultiNameState::EvalExpression (AActor *self) +ExpVal FxMultiNameState::EvalExpression() { ExpVal ret; ret.Type = VAL_State; - ret.pointer = self->GetClass()->FindState(names.Size(), &names[0]); + ret.pointer = NULL; if (ret.pointer == NULL) { const char *dot=""; @@ -3850,7 +3845,7 @@ ExpVal FxMultiNameState::EvalExpression (AActor *self) Printf("%s%s", dot, names[i].GetChars()); dot = "."; } - Printf("' not found in %s\n", self->GetClass()->TypeName.GetChars()); + Printf("' not found in\n"); } return ret; } @@ -3978,7 +3973,7 @@ ExpEmit FxDamageValue::Emit(VMFunctionBuilder *build) { if (val->isConstant()) { - build->EmitRetInt(0, false, val->EvalExpression(NULL).Int); + build->EmitRetInt(0, false, val->EvalExpression().Int); } else { diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index f7f310c2b..3559ee592 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -196,7 +196,7 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, char type, bool con // //========================================================================== -static void ParseConstant (FScanner &sc, PSymbolTable * symt, PClassActor *cls) +static void ParseConstant (FScanner &sc, PSymbolTable *symt, PClassActor *cls) { // Read the type and make sure it's int or float. if (sc.CheckToken(TK_Int) || sc.CheckToken(TK_Float)) @@ -208,7 +208,7 @@ static void ParseConstant (FScanner &sc, PSymbolTable * symt, PClassActor *cls) FxExpression *expr = ParseExpression (sc, cls); sc.MustGetToken(';'); - ExpVal val = expr->EvalExpression(NULL); + ExpVal val = expr->EvalExpression(); delete expr; PSymbolConst *sym = new PSymbolConst(symname); if (type == TK_Int) @@ -256,7 +256,7 @@ static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClassActor *cls) if (sc.CheckToken('=')) { FxExpression *expr = ParseExpression (sc, cls); - currvalue = expr->EvalExpression(NULL).GetInt(); + currvalue = expr->EvalExpression().GetInt(); delete expr; } PSymbolConst *sym = new PSymbolConst(symname); @@ -335,7 +335,7 @@ static void ParseNativeVariable (FScanner &sc, PSymbolTable *symt, PClassActor * if (sc.CheckToken('[')) { FxExpression *expr = ParseExpression (sc, cls); - int maxelems = expr->EvalExpression(NULL).GetInt(); + int maxelems = expr->EvalExpression().GetInt(); delete expr; sc.MustGetToken(']'); valuetype.MakeArray(maxelems); @@ -402,7 +402,7 @@ static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cl if (sc.CheckToken('[')) { FxExpression *expr = ParseExpression(sc, cls); - int maxelems = expr->EvalExpression(NULL).GetInt(); + int maxelems = expr->EvalExpression().GetInt(); delete expr; sc.MustGetToken(']'); if (maxelems <= 0) From 241622300e99ad7d02ad5c01308ea9636857d828 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sun, 28 Jul 2013 19:40:48 -0500 Subject: [PATCH 105/232] Removed some EvalExpression implementations - Removed EvalExpression() implementations from some subclasses of FxExpression that don't make any sense in the context of evaluating a constant value. --- src/thingdef/thingdef_exp.h | 5 -- src/thingdef/thingdef_expression.cpp | 97 +--------------------------- 2 files changed, 1 insertion(+), 101 deletions(-) diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index c88260ac0..3b4c78864 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -667,7 +667,6 @@ public: ~FxRandom(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -681,7 +680,6 @@ class FxFRandom : public FxRandom { public: FxFRandom(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos); - ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -702,7 +700,6 @@ public: ~FxRandom2(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -757,7 +754,6 @@ class FxSelf : public FxExpression public: FxSelf(const FScriptPosition&); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -822,7 +818,6 @@ public: FxActionSpecialCall(FxExpression *self, int special, FArgumentList *args, const FScriptPosition &pos); ~FxActionSpecialCall(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 7946cfc07..d68ba59e7 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -2365,30 +2365,6 @@ FxExpression *FxRandom::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxRandom::EvalExpression() -{ - ExpVal val; - val.Type = VAL_Int; - - if (min != NULL && max != NULL) - { - int minval = min->EvalExpression().GetInt(); - int maxval = max->EvalExpression().GetInt(); - - if (maxval < minval) - { - swapvalues (maxval, minval); - } - - val.Int = (*rng)(maxval - minval + 1) + minval; - } - else - { - val.Int = (*rng)(); - } - return val; -} - int DecoRandom(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) { assert(numparam >= 1 && numparam <= 3); @@ -2462,32 +2438,6 @@ FxFRandom::FxFRandom(FRandom *r, FxExpression *mi, FxExpression *ma, const FScri // //========================================================================== -ExpVal FxFRandom::EvalExpression() -{ - ExpVal val; - val.Type = VAL_Float; - int random = (*rng)(0x40000000); - double frandom = random / double(0x40000000); - - if (min != NULL && max != NULL) - { - double minval = min->EvalExpression().GetFloat(); - double maxval = max->EvalExpression().GetFloat(); - - if (maxval < minval) - { - swapvalues (maxval, minval); - } - - val.Float = frandom * (maxval - minval) + minval; - } - else - { - val.Float = frandom; - } - return val; -} - int DecoFRandom(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) { assert(numparam == 1 || numparam == 3); @@ -2584,16 +2534,6 @@ FxExpression *FxRandom2::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxRandom2::EvalExpression() -{ - ExpVal maskval = mask->EvalExpression(); - int imaskval = maskval.GetInt(); - - maskval.Type = VAL_Int; - maskval.Int = rng->Random2(imaskval); - return maskval; -} - ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) { // Call the DecoRandom function to generate the random number. @@ -2749,18 +2689,9 @@ FxExpression *FxSelf::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxSelf::EvalExpression() -{ - ExpVal ret; - - ret.Type = VAL_Object; - ret.pointer = NULL; - return ret; -} - ExpEmit FxSelf::Emit(VMFunctionBuilder *build) { - // self is always the first pointer passed to the function; + // self is always the first pointer passed to the function ExpEmit me(0, REGT_POINTER); me.Fixed = true; return me; @@ -3363,32 +3294,6 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxActionSpecialCall::EvalExpression() -{ - int v[5] = {0,0,0,0,0}; - int special = Special; - - if (ArgList != NULL) - { - for(unsigned i = 0; i < ArgList->Size(); i++) - { - if (special < 0) - { - special = -special; - v[i] = -(*ArgList)[i]->EvalExpression().GetName(); - } - else - { - v[i] = (*ArgList)[i]->EvalExpression().GetInt(); - } - } - } - ExpVal ret; - ret.Type = VAL_Int; - ret.Int = P_ExecuteSpecial(special, NULL, NULL, false, v[0], v[1], v[2], v[3], v[4]); - return ret; -} - int DecoCallLineSpecial(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) { assert(numparam > 2 && numparam < 7); From 0468b1f9cef9864a7cd6f435f2e3961599e1f795 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sun, 28 Jul 2013 20:05:07 -0500 Subject: [PATCH 106/232] Delete default expressions for action definitions - After StateParams was removed in commit 4a1fbdb, the expressions for default paramaters that ParseActionDef() created went nowhere and were lost. Properly throw them away by deleting them as soon as they've been parsed. --- src/thingdef/thingdef_parse.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 3559ee592..53c233685 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -897,8 +897,6 @@ static void ParseActionDef (FScanner &sc, PClassActor *cls) const AFuncDesc *afd; FName funcname; FString args; - TArray<FxExpression *> DefaultParams; - bool hasdefaults = false; if (sc.LumpNum == -1 || Wads.GetLumpFile(sc.LumpNum) > 0) { @@ -979,18 +977,12 @@ static void ParseActionDef (FScanner &sc, PClassActor *cls) sc.UnGet(); } - FxExpression *def; if (sc.CheckToken('=')) { - hasdefaults = true; flags |= OPTIONAL; - def = ParseParameter(sc, cls, type, true); + FxExpression *def = ParseParameter(sc, cls, type, true); + delete def; } - else - { - def = NULL; - } - DefaultParams.Push(def); if (!(flags & OPTIONAL) && type != '+') { From ff7b1f6e5e3c7a2ef86a8ac40d30cf7f16291c75 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sun, 28 Jul 2013 20:22:47 -0500 Subject: [PATCH 107/232] Add degree variants of FLOP operations - Added versions of the trig operations supported by FLOP that can work with degrees directly instead of radians. - Reorder FLOPs into more sensible groupings. --- src/zscript/vm.h | 27 ++++++++++++++++++--------- src/zscript/vmdisasm.cpp | 29 +++++++++++++++++++---------- src/zscript/vmexec.h | 25 +++++++++++++++++-------- 3 files changed, 54 insertions(+), 27 deletions(-) diff --git a/src/zscript/vm.h b/src/zscript/vm.h index 2d87b7209..d3e4580ce 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -79,21 +79,30 @@ enum { FLOP_ABS, FLOP_NEG, - FLOP_ACOS, - FLOP_ASIN, - FLOP_ATAN, - FLOP_COS, - FLOP_COSH, FLOP_EXP, FLOP_LOG, FLOP_LOG10, - FLOP_SIN, - FLOP_SINH, - FLOP_TAN, - FLOP_TANH, FLOP_SQRT, FLOP_CEIL, FLOP_FLOOR, + + FLOP_ACOS, // This group works with radians + FLOP_ASIN, + FLOP_ATAN, + FLOP_COS, + FLOP_SIN, + FLOP_TAN, + + FLOP_ACOS_DEG, // This group works with degrees + FLOP_ASIN_DEG, + FLOP_ATAN_DEG, + FLOP_COS_DEG, + FLOP_SIN_DEG, + FLOP_TAN_DEG, + + FLOP_COSH, + FLOP_SINH, + FLOP_TANH, }; // Cast operations diff --git a/src/zscript/vmdisasm.cpp b/src/zscript/vmdisasm.cpp index 3cfcd821d..35ca6aa1f 100644 --- a/src/zscript/vmdisasm.cpp +++ b/src/zscript/vmdisasm.cpp @@ -101,21 +101,30 @@ static const char *const FlopNames[] = { "abs", "neg", - "acos", - "asin", - "atan", - "cos", - "cosh", "exp", "log", "log10", - "sin", - "sinh", - "tan", - "tanh", "sqrt", "ceil", - "floor" + "floor", + + "acos rad", + "asin rad", + "atan rad", + "cos rad", + "sin rad", + "tan rad", + + "acos deg", + "asin deg", + "atan deg", + "cos deg", + "sin deg", + "tan deg", + + "cosh", + "sinh", + "tanh", }; static int print_reg(FILE *out, int col, int arg, int mode, int immshift, const VMScriptFunction *func); diff --git a/src/zscript/vmexec.h b/src/zscript/vmexec.h index e901e5f03..be32dd3c1 100644 --- a/src/zscript/vmexec.h +++ b/src/zscript/vmexec.h @@ -1369,21 +1369,30 @@ static double DoFLOP(int flop, double v) { case FLOP_ABS: return fabs(v); case FLOP_NEG: return -v; + case FLOP_EXP: return exp(v); + case FLOP_LOG: return log(v); + case FLOP_LOG10: return log10(v); + case FLOP_SQRT: return sqrt(v); + case FLOP_CEIL: return ceil(v); + case FLOP_FLOOR: return floor(v); + case FLOP_ACOS: return acos(v); case FLOP_ASIN: return asin(v); case FLOP_ATAN: return atan(v); case FLOP_COS: return cos(v); - case FLOP_COSH: return cosh(v); - case FLOP_EXP: return exp(v); - case FLOP_LOG: return log(v); - case FLOP_LOG10: return log10(v); case FLOP_SIN: return sin(v); - case FLOP_SINH: return sinh(v); case FLOP_TAN: return tan(v); + + case FLOP_ACOS_DEG: return acos(v) * (180 / M_PI); + case FLOP_ASIN_DEG: return asin(v) * (180 / M_PI); + case FLOP_ATAN_DEG: return atan(v) * (180 / M_PI); + case FLOP_COS_DEG: return cos(v * (M_PI / 180)); + case FLOP_SIN_DEG: return sin(v * (M_PI / 180)); + case FLOP_TAN_DEG: return tan(v * (M_PI / 180)); + + case FLOP_COSH: return cosh(v); + case FLOP_SINH: return sinh(v); case FLOP_TANH: return tanh(v); - case FLOP_SQRT: return sqrt(v); - case FLOP_CEIL: return ceil(v); - case FLOP_FLOOR: return floor(v); } assert(0); return 0; From c810b4d724b5c1078177603f0629f7a8467f2ea2 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sun, 28 Jul 2013 20:29:25 -0500 Subject: [PATCH 108/232] Use new degree FLOPs for DECORATE expressions. - Now that the VM supports degrees, use those instructions when emitting code for cos and sin DECORATE expressions. (This looks like it also fixed a bug where sqrt also did the degree to radian conversion.) --- src/thingdef/thingdef_expression.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index d68ba59e7..620082b4d 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3458,11 +3458,10 @@ ExpEmit FxGlobalFunctionCall::Emit(VMFunctionBuilder *build) ExpEmit v = (*ArgList)[0]->Emit(build); assert(!v.Konst && v.RegType == REGT_FLOAT); - build->Emit(OP_MULF_RK, v.RegNum, v.RegNum, build->GetConstantFloat(M_PI / 180.0)); build->Emit(OP_FLOP, v.RegNum, v.RegNum, (Name == NAME_Sqrt) ? FLOP_SQRT : - (Name == NAME_Sin) ? FLOP_SIN : - FLOP_COS); + (Name == NAME_Sin) ? FLOP_SIN_DEG : + FLOP_COS_DEG); return v; } From 58f088c1ab4a960d4494677d3af3ffb39f4a9770 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 30 Jul 2013 22:52:27 -0500 Subject: [PATCH 109/232] Remove FxExpression::EvalExpression() entirely - For the purposes of getting constant values from expressions, the only class where Resolve doesn't duplicate the functionality of EvalExpression was FxConstant. So, every other class has had its EvalExpression taken away, and FxConstant has had it renamed to GetValue. --- src/thingdef/thingdef_exp.h | 26 +- src/thingdef/thingdef_expression.cpp | 462 +++------------------------ src/thingdef/thingdef_parse.cpp | 75 +++-- 3 files changed, 98 insertions(+), 465 deletions(-) diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 3b4c78864..239c2ad88 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -230,7 +230,6 @@ public: virtual FxExpression *Resolve(FCompileContext &ctx); FxExpression *ResolveAsBoolean(FCompileContext &ctx); - virtual ExpVal EvalExpression(); virtual bool isConstant() const; virtual void RequestAddress(); @@ -377,7 +376,11 @@ public: { return true; } - ExpVal EvalExpression(); + + ExpVal GetValue() const + { + return value; + } ExpEmit Emit(VMFunctionBuilder *build); }; @@ -398,7 +401,6 @@ public: ~FxIntCast(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -412,7 +414,6 @@ public: ~FxFloatCast(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -448,7 +449,6 @@ public: FxMinusSign(FxExpression*); ~FxMinusSign(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -466,7 +466,6 @@ public: FxUnaryNotBitwise(FxExpression*); ~FxUnaryNotBitwise(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -484,7 +483,6 @@ public: FxUnaryNotBoolean(FxExpression*); ~FxUnaryNotBoolean(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -519,7 +517,6 @@ public: FxAddSub(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -535,7 +532,6 @@ public: FxMulDiv(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -551,7 +547,6 @@ public: FxCompareRel(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -567,7 +562,6 @@ public: FxCompareEq(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -583,7 +577,6 @@ public: FxBinaryInt(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -604,7 +597,6 @@ public: ~FxBinaryLogical(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -625,7 +617,6 @@ public: ~FxConditional(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -645,7 +636,6 @@ public: ~FxAbs(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -719,7 +709,6 @@ public: FxGlobalVariable(PSymbolVariable*, const FScriptPosition&); FxExpression *Resolve(FCompileContext&); void RequestAddress(); - ExpVal EvalExpression(); }; //========================================================================== @@ -739,7 +728,6 @@ public: ~FxClassMember(); FxExpression *Resolve(FCompileContext&); void RequestAddress(); - ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -774,7 +762,6 @@ public: ~FxArrayElement(); FxExpression *Resolve(FCompileContext&); //void RequestAddress(); - ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -837,7 +824,6 @@ public: FxGlobalFunctionCall(FName fname, FArgumentList *args, const FScriptPosition &pos); ~FxGlobalFunctionCall(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -858,7 +844,6 @@ public: FxClassTypeCast(const PClass *dtype, FxExpression *x); ~FxClassTypeCast(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -895,7 +880,6 @@ public: FxMultiNameState(const char *statestring, const FScriptPosition &pos); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression(); ExpEmit Emit(VMFunctionBuilder *build); }; diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 620082b4d..c7e8f9ef7 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -198,22 +198,6 @@ static ExpVal GetVariableValue (void *address, FExpressionType &type) // //========================================================================== -ExpVal FxExpression::EvalExpression() -{ - ScriptPosition.Message(MSG_ERROR, "Unresolved expression found"); - ExpVal val; - - val.Type = VAL_Int; - val.Int = 0; - return val; -} - -//========================================================================== -// -// -// -//========================================================================== - ExpEmit FxExpression::Emit (VMFunctionBuilder *build) { ScriptPosition.Message(MSG_ERROR, "Unemitted expression found"); @@ -324,7 +308,7 @@ ExpEmit FxParameter::Emit(VMFunctionBuilder *build) { if (Operand->isConstant()) { - ExpVal val = Operand->EvalExpression(); + ExpVal val = static_cast<FxConstant *>(Operand)->GetValue(); if (val.Type == VAL_Int || val.Type == VAL_Sound || val.Type == VAL_Name || val.Type == VAL_Color) { build->EmitParamInt(val.Int); @@ -375,17 +359,6 @@ ExpEmit FxParameter::Emit(VMFunctionBuilder *build) // //========================================================================== -ExpVal FxConstant::EvalExpression() -{ - return value; -} - -//========================================================================== -// -// -// -//========================================================================== - FxExpression *FxConstant::MakeConstant(PSymbol *sym, const FScriptPosition &pos) { FxExpression *x; @@ -500,7 +473,7 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx) { if (basex->isConstant()) { - ExpVal constval = basex->EvalExpression(); + ExpVal constval = static_cast<FxConstant *>(basex)->GetValue(); FxExpression *x = new FxConstant(constval.GetInt(), ScriptPosition); delete this; return x; @@ -521,14 +494,6 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxIntCast::EvalExpression() -{ - ExpVal baseval = basex->EvalExpression(); - baseval.Int = baseval.GetInt(); - baseval.Type = VAL_Int; - return baseval; -} - ExpEmit FxIntCast::Emit(VMFunctionBuilder *build) { ExpEmit from = basex->Emit(build); @@ -585,7 +550,7 @@ FxExpression *FxFloatCast::Resolve(FCompileContext &ctx) { if (basex->isConstant()) { - ExpVal constval = basex->EvalExpression(); + ExpVal constval = static_cast<FxConstant *>(basex)->GetValue(); FxExpression *x = new FxConstant(constval.GetFloat(), ScriptPosition); delete this; return x; @@ -606,14 +571,6 @@ FxExpression *FxFloatCast::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxFloatCast::EvalExpression() -{ - ExpVal baseval = basex->EvalExpression(); - baseval.Float = baseval.GetFloat(); - baseval.Type = VAL_Float; - return baseval; -} - ExpEmit FxFloatCast::Emit(VMFunctionBuilder *build) { ExpEmit from = basex->Emit(build); @@ -717,7 +674,7 @@ FxExpression *FxMinusSign::Resolve(FCompileContext& ctx) { if (Operand->isConstant()) { - ExpVal val = Operand->EvalExpression(); + ExpVal val = static_cast<FxConstant *>(Operand)->GetValue(); FxExpression *e = val.Type == VAL_Int? new FxConstant(-val.Int, ScriptPosition) : new FxConstant(-val.Float, ScriptPosition); @@ -741,23 +698,6 @@ FxExpression *FxMinusSign::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxMinusSign::EvalExpression() -{ - ExpVal ret; - - if (ValueType == VAL_Int) - { - ret.Int = -Operand->EvalExpression().GetInt(); - ret.Type = VAL_Int; - } - else - { - ret.Float = -Operand->EvalExpression().GetFloat(); - ret.Type = VAL_Float; - } - return ret; -} - ExpEmit FxMinusSign::Emit(VMFunctionBuilder *build) { assert(ValueType.Type == Operand->ValueType.Type); @@ -831,7 +771,7 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx) if (Operand->isConstant()) { - int result = ~Operand->EvalExpression().GetInt(); + int result = ~static_cast<FxConstant *>(Operand)->GetValue().GetInt(); FxExpression *e = new FxConstant(result, ScriptPosition); delete this; return e; @@ -846,15 +786,6 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxUnaryNotBitwise::EvalExpression() -{ - ExpVal ret; - - ret.Int = ~Operand->EvalExpression().GetInt(); - ret.Type = VAL_Int; - return ret; -} - ExpEmit FxUnaryNotBitwise::Emit(VMFunctionBuilder *build) { assert(ValueType.Type == Operand->ValueType.Type); @@ -913,7 +844,7 @@ FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx) { if (Operand->isConstant()) { - bool result = !Operand->EvalExpression().GetBool(); + bool result = !static_cast<FxConstant *>(Operand)->GetValue().GetBool(); FxExpression *e = new FxConstant(result, ScriptPosition); delete this; return e; @@ -935,15 +866,6 @@ FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxUnaryNotBoolean::EvalExpression() -{ - ExpVal ret; - - ret.Int = !Operand->EvalExpression().GetBool(); - ret.Type = VAL_Int; - return ret; -} - ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build) { ExpEmit from = Operand->Emit(build); @@ -1089,8 +1011,8 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx) if (ValueType == VAL_Float) { double v; - double v1 = left->EvalExpression().GetFloat(); - double v2 = right->EvalExpression().GetFloat(); + double v1 = static_cast<FxConstant *>(left)->GetValue().GetFloat(); + double v2 = static_cast<FxConstant *>(right)->GetValue().GetFloat(); v = Operator == '+'? v1 + v2 : Operator == '-'? v1 - v2 : 0; @@ -1102,8 +1024,8 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx) else { int v; - int v1 = left->EvalExpression().GetInt(); - int v2 = right->EvalExpression().GetInt(); + int v1 = static_cast<FxConstant *>(left)->GetValue().GetInt(); + int v2 = static_cast<FxConstant *>(right)->GetValue().GetInt(); v = Operator == '+'? v1 + v2 : Operator == '-'? v1 - v2 : 0; @@ -1124,32 +1046,6 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxAddSub::EvalExpression() -{ - ExpVal ret; - - if (ValueType == VAL_Float) - { - double v1 = left->EvalExpression().GetFloat(); - double v2 = right->EvalExpression().GetFloat(); - - ret.Type = VAL_Float; - ret.Float = Operator == '+'? v1 + v2 : - Operator == '-'? v1 - v2 : 0; - } - else - { - int v1 = left->EvalExpression().GetInt(); - int v2 = right->EvalExpression().GetInt(); - - ret.Type = VAL_Int; - ret.Int = Operator == '+'? v1 + v2 : - Operator == '-'? v1 - v2 : 0; - - } - return ret; -} - ExpEmit FxAddSub::Emit(VMFunctionBuilder *build) { assert(Operator == '+' || Operator == '-'); @@ -1241,8 +1137,8 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) if (ValueType == VAL_Float) { double v; - double v1 = left->EvalExpression().GetFloat(); - double v2 = right->EvalExpression().GetFloat(); + double v1 = static_cast<FxConstant *>(left)->GetValue().GetFloat(); + double v2 = static_cast<FxConstant *>(right)->GetValue().GetFloat(); if (Operator != '*' && v2 == 0) { @@ -1262,8 +1158,8 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) else { int v; - int v1 = left->EvalExpression().GetInt(); - int v2 = right->EvalExpression().GetInt(); + int v1 = static_cast<FxConstant *>(left)->GetValue().GetInt(); + int v2 = static_cast<FxConstant *>(right)->GetValue().GetInt(); if (Operator != '*' && v2 == 0) { @@ -1293,44 +1189,6 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxMulDiv::EvalExpression() -{ - ExpVal ret; - - if (ValueType == VAL_Float) - { - double v1 = left->EvalExpression().GetFloat(); - double v2 = right->EvalExpression().GetFloat(); - - if (Operator != '*' && v2 == 0) - { - I_Error("Division by 0"); - } - - ret.Type = VAL_Float; - ret.Float = Operator == '*'? v1 * v2 : - Operator == '/'? v1 / v2 : - Operator == '%'? fmod(v1, v2) : 0; - } - else - { - int v1 = left->EvalExpression().GetInt(); - int v2 = right->EvalExpression().GetInt(); - - if (Operator != '*' && v2 == 0) - { - I_Error("Division by 0"); - } - - ret.Type = VAL_Int; - ret.Int = Operator == '*'? v1 * v2 : - Operator == '/'? v1 / v2 : - Operator == '%'? v1 % v2 : 0; - - } - return ret; -} - ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build) { ExpEmit op1 = left->Emit(build); @@ -1425,8 +1283,8 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) if (ValueType == VAL_Float) { - double v1 = left->EvalExpression().GetFloat(); - double v2 = right->EvalExpression().GetFloat(); + double v1 = static_cast<FxConstant *>(left)->GetValue().GetFloat(); + double v2 = static_cast<FxConstant *>(right)->GetValue().GetFloat(); v = Operator == '<'? v1 < v2 : Operator == '>'? v1 > v2 : Operator == TK_Geq? v1 >= v2 : @@ -1434,8 +1292,8 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) } else { - int v1 = left->EvalExpression().GetInt(); - int v2 = right->EvalExpression().GetInt(); + int v1 = static_cast<FxConstant *>(left)->GetValue().GetInt(); + int v2 = static_cast<FxConstant *>(right)->GetValue().GetInt(); v = Operator == '<'? v1 < v2 : Operator == '>'? v1 > v2 : Operator == TK_Geq? v1 >= v2 : @@ -1457,33 +1315,6 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxCompareRel::EvalExpression() -{ - ExpVal ret; - - ret.Type = VAL_Int; - - if (left->ValueType == VAL_Float || right->ValueType == VAL_Float) - { - double v1 = left->EvalExpression().GetFloat(); - double v2 = right->EvalExpression().GetFloat(); - ret.Int = Operator == '<'? v1 < v2 : - Operator == '>'? v1 > v2 : - Operator == TK_Geq? v1 >= v2 : - Operator == TK_Leq? v1 <= v2 : 0; - } - else - { - int v1 = left->EvalExpression().GetInt(); - int v2 = right->EvalExpression().GetInt(); - ret.Int = Operator == '<'? v1 < v2 : - Operator == '>'? v1 > v2 : - Operator == TK_Geq? v1 >= v2 : - Operator == TK_Leq? v1 <= v2 : 0; - } - return ret; -} - ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build) { ExpEmit op1 = left->Emit(build); @@ -1584,14 +1415,14 @@ cont: if (ValueType == VAL_Float) { - double v1 = left->EvalExpression().GetFloat(); - double v2 = right->EvalExpression().GetFloat(); + double v1 = static_cast<FxConstant *>(left)->GetValue().GetFloat(); + double v2 = static_cast<FxConstant *>(right)->GetValue().GetFloat(); v = Operator == TK_Eq? v1 == v2 : v1 != v2; } else { - int v1 = left->EvalExpression().GetInt(); - int v2 = right->EvalExpression().GetInt(); + int v1 = static_cast<FxConstant *>(left)->GetValue().GetInt(); + int v2 = static_cast<FxConstant *>(right)->GetValue().GetInt(); v = Operator == TK_Eq? v1 == v2 : v1 != v2; } FxExpression *e = new FxConstant(v, ScriptPosition); @@ -1609,32 +1440,6 @@ cont: // //========================================================================== -ExpVal FxCompareEq::EvalExpression() -{ - ExpVal ret; - - ret.Type = VAL_Int; - - if (left->ValueType == VAL_Float || right->ValueType == VAL_Float) - { - double v1 = left->EvalExpression().GetFloat(); - double v2 = right->EvalExpression().GetFloat(); - ret.Int = Operator == TK_Eq? v1 == v2 : v1 != v2; - } - else if (left->ValueType == VAL_Int) - { - int v1 = left->EvalExpression().GetInt(); - int v2 = right->EvalExpression().GetInt(); - ret.Int = Operator == TK_Eq? v1 == v2 : v1 != v2; - } - else - { - // Implement pointer comparison - ret.Int = 0; - } - return ret; -} - ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build) { ExpEmit op1 = left->Emit(build); @@ -1725,8 +1530,8 @@ FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx) } else if (left->isConstant() && right->isConstant()) { - int v1 = left->EvalExpression().GetInt(); - int v2 = right->EvalExpression().GetInt(); + int v1 = static_cast<FxConstant *>(left)->GetValue().GetInt(); + int v2 = static_cast<FxConstant *>(right)->GetValue().GetInt(); FxExpression *e = new FxConstant( Operator == TK_LShift? v1 << v2 : @@ -1748,25 +1553,6 @@ FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxBinaryInt::EvalExpression() -{ - int v1 = left->EvalExpression().GetInt(); - int v2 = right->EvalExpression().GetInt(); - - ExpVal ret; - - ret.Type = VAL_Int; - ret.Int = - Operator == TK_LShift? v1 << v2 : - Operator == TK_RShift? v1 >> v2 : - Operator == TK_URShift? int((unsigned int)(v1) >> v2) : - Operator == '&'? v1 & v2 : - Operator == '|'? v1 | v2 : - Operator == '^'? v1 ^ v2 : 0; - - return ret; -} - ExpEmit FxBinaryInt::Emit(VMFunctionBuilder *build) { assert(left->ValueType == VAL_Int); @@ -1795,7 +1581,7 @@ ExpEmit FxBinaryInt::Emit(VMFunctionBuilder *build) { // Shift instructions use right-hand immediates instead of constant registers. if (right->isConstant()) { - rop = right->EvalExpression().GetInt(); + rop = static_cast<FxConstant *>(right)->GetValue().GetInt(); op2.Konst = true; } else @@ -1886,8 +1672,8 @@ FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx) int b_left=-1, b_right=-1; - if (left->isConstant()) b_left = left->EvalExpression().GetBool(); - if (right->isConstant()) b_right = right->EvalExpression().GetBool(); + if (left->isConstant()) b_left = static_cast<FxConstant *>(left)->GetValue().GetBool(); + if (right->isConstant()) b_right = static_cast<FxConstant *>(right)->GetValue().GetBool(); // Do some optimizations. This will throw out all sub-expressions that are not // needed to retrieve the final result. @@ -1966,25 +1752,6 @@ FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxBinaryLogical::EvalExpression() -{ - bool b_left = left->EvalExpression().GetBool(); - ExpVal ret; - - ret.Type = VAL_Int; - ret.Int = false; - - if (Operator == TK_AndAnd) - { - ret.Int = (b_left && right->EvalExpression().GetBool()); - } - else if (Operator == TK_OrOr) - { - ret.Int = (b_left || right->EvalExpression().GetBool()); - } - return ret; -} - ExpEmit FxBinaryLogical::Emit(VMFunctionBuilder *build) { // This is not the "right" way to do these, but it works for now. @@ -2088,7 +1855,7 @@ FxExpression *FxConditional::Resolve(FCompileContext& ctx) if (condition->isConstant()) { - ExpVal condval = condition->EvalExpression(); + ExpVal condval = static_cast<FxConstant *>(condition)->GetValue(); bool result = condval.GetBool(); FxExpression *e = result? truex:falsex; @@ -2121,15 +1888,6 @@ FxExpression *FxConditional::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxConditional::EvalExpression() -{ - ExpVal condval = condition->EvalExpression(); - bool result = condval.GetBool(); - - FxExpression *e = result? truex:falsex; - return e->EvalExpression(); -} - ExpEmit FxConditional::Emit(VMFunctionBuilder *build) { ExpEmit out; @@ -2148,7 +1906,7 @@ ExpEmit FxConditional::Emit(VMFunctionBuilder *build) if (truex->isConstant() && truex->ValueType == VAL_Int) { out = ExpEmit(build, REGT_INT); - build->EmitLoadInt(out.RegNum, truex->EvalExpression().GetInt()); + build->EmitLoadInt(out.RegNum, static_cast<FxConstant *>(truex)->GetValue().GetInt()); } else { @@ -2171,7 +1929,7 @@ ExpEmit FxConditional::Emit(VMFunctionBuilder *build) build->BackpatchToHere(patchspot); if (falsex->isConstant() && falsex->ValueType == VAL_Int) { - build->EmitLoadInt(out.RegNum, falsex->EvalExpression().GetInt()); + build->EmitLoadInt(out.RegNum, static_cast<FxConstant *>(falsex)->GetValue().GetInt()); } else { @@ -2245,7 +2003,7 @@ FxExpression *FxAbs::Resolve(FCompileContext &ctx) } else if (val->isConstant()) { - ExpVal value = val->EvalExpression(); + ExpVal value = static_cast<FxConstant *>(val)->GetValue(); switch (value.Type) { case VAL_Int: @@ -2274,23 +2032,6 @@ FxExpression *FxAbs::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxAbs::EvalExpression() -{ - ExpVal value = val->EvalExpression(); - switch (value.Type) - { - default: - case VAL_Int: - value.Int = abs(value.Int); - break; - - case VAL_Float: - value.Float = fabs(value.Float); - break; - } - return value; -} - ExpEmit FxAbs::Emit(VMFunctionBuilder *build) { ExpEmit absofsteal = val->Emit(build); @@ -2761,28 +2502,6 @@ FxExpression *FxGlobalVariable::Resolve(FCompileContext&) // //========================================================================== -ExpVal FxGlobalVariable::EvalExpression() -{ - ExpVal ret; - - if (!AddressRequested) - { - ret = GetVariableValue((void*)var->offset, var->ValueType); - } - else - { - ret.pointer = (void*)var->offset; - ret.Type = VAL_Pointer; - } - return ret; -} - -//========================================================================== -// -// -// -//========================================================================== - FxClassMember::FxClassMember(FxExpression *x, PSymbolVariable* mem, const FScriptPosition &pos) : FxExpression(pos) { @@ -2858,42 +2577,6 @@ FxExpression *FxClassMember::Resolve(FCompileContext &ctx) return this; } -//========================================================================== -// -// -// -//========================================================================== - -ExpVal FxClassMember::EvalExpression() -{ - char *object = NULL; - if (classx->ValueType == VAL_Class) - { - // not implemented yet - } - else - { - object = classx->EvalExpression().GetPointer<char>(); - } - if (object == NULL) - { - I_Error("Accessing member variable without valid object"); - } - - ExpVal ret; - - if (!AddressRequested) - { - ret = GetVariableValue(object + membervar->offset, membervar->ValueType); - } - else - { - ret.pointer = object + membervar->offset; - ret.Type = VAL_Pointer; - } - return ret; -} - ExpEmit FxClassMember::Emit(VMFunctionBuilder *build) { ExpEmit obj = classx->Emit(build); @@ -3071,23 +2754,6 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxArrayElement::EvalExpression() -{ - int * arraystart = Array->EvalExpression().GetPointer<int>(); - int indexval = index->EvalExpression().GetInt(); - - if (indexval < 0 || indexval >= Array->ValueType.size) - { - I_Error("Array index out of bounds"); - } - - ExpVal ret; - - ret.Int = arraystart[indexval]; - ret.Type = VAL_Int; - return ret; -} - ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) { ExpEmit start = Array->Emit(build); @@ -3100,7 +2766,7 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) } if (index->isConstant()) { - int indexval = index->EvalExpression().GetInt(); + int indexval = static_cast<FxConstant *>(index)->GetValue().GetInt(); if (indexval < 0 || indexval >= Array->ValueType.size) { I_Error("Array index out of bounds"); @@ -3326,14 +2992,14 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) { assert(argex->ValueType == VAL_Name); assert(argex->isConstant()); - build->EmitParamInt(-argex->EvalExpression().GetName()); + build->EmitParamInt(-static_cast<FxConstant *>(argex)->GetValue().GetName()); } else { assert(argex->ValueType == VAL_Int); if (argex->isConstant()) { - build->EmitParamInt(argex->EvalExpression().GetInt()); + build->EmitParamInt(static_cast<FxConstant *>(argex)->GetValue().GetInt()); } else { @@ -3408,7 +3074,7 @@ FxExpression *FxGlobalFunctionCall::Resolve(FCompileContext& ctx) } if ((*ArgList)[0]->isConstant()) { - double v = (*ArgList)[0]->EvalExpression().GetFloat(); + double v = static_cast<FxConstant *>((*ArgList)[0])->GetValue().GetFloat(); if (Name == NAME_Sqrt) { v = sqrt(v); @@ -3435,24 +3101,6 @@ FxExpression *FxGlobalFunctionCall::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxGlobalFunctionCall::EvalExpression() -{ - double v = (*ArgList)[0]->EvalExpression().GetFloat(); - ExpVal ret; - ret.Type = VAL_Float; - - if (Name == NAME_Sqrt) - { - ret.Float = sqrt(v); - } - else - { - v *= M_PI / 180.0; // convert from degrees to radians - ret.Float = (Name == NAME_Sin) ? sin(v) : cos(v); - } - return ret; -} - ExpEmit FxGlobalFunctionCall::Emit(VMFunctionBuilder *build) { ExpEmit v = (*ArgList)[0]->Emit(build); @@ -3507,7 +3155,7 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) if (basex->isConstant()) { - FName clsname = basex->EvalExpression().GetName(); + FName clsname = static_cast<FxConstant *>(basex)->GetValue().GetName(); const PClass *cls = NULL; if (clsname != NAME_None) @@ -3550,23 +3198,6 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxClassTypeCast::EvalExpression() -{ - FName clsname = basex->EvalExpression().GetName(); - const PClass *cls = PClass::FindClass(clsname); - - if (!cls->IsDescendantOf(desttype)) - { - Printf("class '%s' is not compatible with '%s'", clsname.GetChars(), desttype->TypeName.GetChars()); - cls = NULL; - } - - ExpVal ret; - ret.Type = VAL_Class; - ret.pointer = (void*)cls; - return ret; -} - int DecoNameToClass(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) { assert(numparam == 2); @@ -3735,25 +3366,6 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxMultiNameState::EvalExpression() -{ - ExpVal ret; - ret.Type = VAL_State; - ret.pointer = NULL; - if (ret.pointer == NULL) - { - const char *dot=""; - Printf("Jump target '"); - for (unsigned int i=0;i<names.Size();i++) - { - Printf("%s%s", dot, names[i].GetChars()); - dot = "."; - } - Printf("' not found in\n"); - } - return ret; -} - static int DoFindState(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, FName *names, int numnames) { PARAM_OBJECT_AT(0, self, AActor); @@ -3877,7 +3489,7 @@ ExpEmit FxDamageValue::Emit(VMFunctionBuilder *build) { if (val->isConstant()) { - build->EmitRetInt(0, false, val->EvalExpression().Int); + build->EmitRetInt(0, false, static_cast<FxConstant *>(val)->GetValue().Int); } else { diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 53c233685..23d7fd00a 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -208,25 +208,35 @@ static void ParseConstant (FScanner &sc, PSymbolTable *symt, PClassActor *cls) FxExpression *expr = ParseExpression (sc, cls); sc.MustGetToken(';'); - ExpVal val = expr->EvalExpression(); - delete expr; - PSymbolConst *sym = new PSymbolConst(symname); - if (type == TK_Int) + FCompileContext ctx(cls, true, true); + expr = expr->Resolve(ctx); + if (!expr->isConstant()) { - sym->ValueType = VAL_Int; - sym->Value = val.GetInt(); + sc.ScriptMessage("Constant definition is not a constant"); + FScriptPosition::ErrorCounter++; } else { - sym->ValueType = VAL_Float; - sym->Float = val.GetFloat(); - } - if (symt->AddSymbol (sym) == NULL) - { - delete sym; - sc.ScriptMessage ("'%s' is already defined in '%s'.", - symname.GetChars(), cls? cls->TypeName.GetChars() : "Global"); - FScriptPosition::ErrorCounter++; + ExpVal val = static_cast<FxConstant *>(expr)->GetValue(); + delete expr; + PSymbolConst *sym = new PSymbolConst(symname); + if (type == TK_Int) + { + sym->ValueType = VAL_Int; + sym->Value = val.GetInt(); + } + else + { + sym->ValueType = VAL_Float; + sym->Float = val.GetFloat(); + } + if (symt->AddSymbol (sym) == NULL) + { + delete sym; + sc.ScriptMessage ("'%s' is already defined in '%s'.", + symname.GetChars(), cls? cls->TypeName.GetChars() : "Global"); + FScriptPosition::ErrorCounter++; + } } } else @@ -256,7 +266,17 @@ static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClassActor *cls) if (sc.CheckToken('=')) { FxExpression *expr = ParseExpression (sc, cls); - currvalue = expr->EvalExpression().GetInt(); + FCompileContext ctx(cls, true, true); + expr = expr->Resolve(ctx); + if (!expr->isConstant()) + { + sc.ScriptMessage("'%s' must be constant", symname.GetChars()); + FScriptPosition::ErrorCounter++; + } + else + { + currvalue = static_cast<FxConstant *>(expr)->GetValue().GetInt(); + } delete expr; } PSymbolConst *sym = new PSymbolConst(symname); @@ -335,7 +355,13 @@ static void ParseNativeVariable (FScanner &sc, PSymbolTable *symt, PClassActor * if (sc.CheckToken('[')) { FxExpression *expr = ParseExpression (sc, cls); - int maxelems = expr->EvalExpression().GetInt(); + FCompileContext ctx(cls, true, true); + expr = expr->Resolve(ctx); + if (!expr->isConstant()) + { + sc.ScriptError("Array size must be constant"); + } + int maxelems = static_cast<FxConstant *>(expr)->GetValue().GetInt(); delete expr; sc.MustGetToken(']'); valuetype.MakeArray(maxelems); @@ -402,8 +428,19 @@ static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cl if (sc.CheckToken('[')) { FxExpression *expr = ParseExpression(sc, cls); - int maxelems = expr->EvalExpression().GetInt(); - delete expr; + FCompileContext ctx(cls, true, true); + int maxelems; + expr = expr->Resolve(ctx); + if (!expr->isConstant()) + { + sc.ScriptMessage("Array size must be a constant"); + FScriptPosition::ErrorCounter++; + maxelems = 1; + } + else + { + maxelems = static_cast<FxConstant *>(expr)->GetValue().GetInt(); + } sc.MustGetToken(']'); if (maxelems <= 0) { From 09c902ce55197fe42f5d925e0899a02a5c9c1e03 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 2 Aug 2013 21:09:49 -0500 Subject: [PATCH 110/232] Remove isconst from FCompileContext. - It's not used anymore, so keeping it around is pointless. --- src/thingdef/thingdef_exp.h | 4 +--- src/thingdef/thingdef_parse.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 239c2ad88..9097e1ffc 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -62,13 +62,11 @@ struct FCompileContext { PClassActor *cls; bool lax; - bool isconst; - FCompileContext(PClassActor *_cls = NULL, bool _lax = false, bool _isconst = false) + FCompileContext(PClassActor *_cls = NULL, bool _lax = false) { cls = _cls; lax = _lax; - isconst = _isconst; } PSymbol *FindInClass(FName identifier) diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 23d7fd00a..0ac87bb35 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -208,7 +208,7 @@ static void ParseConstant (FScanner &sc, PSymbolTable *symt, PClassActor *cls) FxExpression *expr = ParseExpression (sc, cls); sc.MustGetToken(';'); - FCompileContext ctx(cls, true, true); + FCompileContext ctx(cls, true); expr = expr->Resolve(ctx); if (!expr->isConstant()) { @@ -266,7 +266,7 @@ static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClassActor *cls) if (sc.CheckToken('=')) { FxExpression *expr = ParseExpression (sc, cls); - FCompileContext ctx(cls, true, true); + FCompileContext ctx(cls, true); expr = expr->Resolve(ctx); if (!expr->isConstant()) { @@ -355,7 +355,7 @@ static void ParseNativeVariable (FScanner &sc, PSymbolTable *symt, PClassActor * if (sc.CheckToken('[')) { FxExpression *expr = ParseExpression (sc, cls); - FCompileContext ctx(cls, true, true); + FCompileContext ctx(cls, true); expr = expr->Resolve(ctx); if (!expr->isConstant()) { @@ -428,7 +428,7 @@ static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cl if (sc.CheckToken('[')) { FxExpression *expr = ParseExpression(sc, cls); - FCompileContext ctx(cls, true, true); + FCompileContext ctx(cls, true); int maxelems; expr = expr->Resolve(ctx); if (!expr->isConstant()) From 4f528e383239b61f9a94d31cc27b23c3024dd105 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 2 Aug 2013 21:13:40 -0500 Subject: [PATCH 111/232] Remove lax from FCompileContext - It's always set to true these days, so let's get rid of it. --- src/thingdef/thingdef.cpp | 4 ++-- src/thingdef/thingdef_exp.cpp | 4 +--- src/thingdef/thingdef_exp.h | 4 +--- src/thingdef/thingdef_expression.cpp | 23 +++++++---------------- src/thingdef/thingdef_parse.cpp | 8 ++++---- 5 files changed, 15 insertions(+), 28 deletions(-) diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index ef0be1d23..3868c3fca 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -293,7 +293,7 @@ static void FinishThingdef() } else { - FCompileContext ctx(tcall->ActorClass, true); + FCompileContext ctx(tcall->ActorClass); for (j = 0; j < tcall->Parameters.Size(); ++j) { tcall->Parameters[j]->Resolve(ctx); @@ -358,7 +358,7 @@ static void FinishThingdef() sfunc = dmg->GetFunction(); if (sfunc == NULL) { - FCompileContext ctx(ti, true); + FCompileContext ctx(ti); dmg->Resolve(ctx); VMFunctionBuilder buildit; buildit.Registers[REGT_POINTER].Get(1); // The self pointer diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index a74d1b626..eba794ef6 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -76,9 +76,7 @@ FxExpression *ParseExpression (FScanner &sc, PClassActor *cls) { FxExpression *data = ParseExpressionM (sc, cls); - FCompileContext ctx; - ctx.cls = cls; - ctx.lax = true; + FCompileContext ctx(cls); data = data->Resolve(ctx); return data; diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 9097e1ffc..e6a6d4941 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -61,12 +61,10 @@ extern PSymbolTable GlobalSymbols; struct FCompileContext { PClassActor *cls; - bool lax; - FCompileContext(PClassActor *_cls = NULL, bool _lax = false) + FCompileContext(PClassActor *_cls = NULL) { cls = _cls; - lax = _lax; } PSymbol *FindInClass(FName identifier) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index c7e8f9ef7..f28a3bb8b 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -750,7 +750,7 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx) CHECKRESOLVED(); SAFE_RESOLVE(Operand, ctx); - if (Operand->ValueType == VAL_Float && ctx.lax) + if (Operand->ValueType == VAL_Float /* lax */) { // DECORATE allows floats here so cast them to int. Operand = new FxIntCast(Operand); @@ -1501,7 +1501,7 @@ FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx) CHECKRESOLVED(); if (!ResolveLR(ctx, false)) return NULL; - if (ctx.lax && ValueType == VAL_Float) + if (ValueType == VAL_Float /* lax */) { // For DECORATE which allows floats here. if (left->ValueType != VAL_Int) @@ -2711,7 +2711,7 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) SAFE_RESOLVE(Array,ctx); SAFE_RESOLVE(index,ctx); - if (index->ValueType == VAL_Float && ctx.lax) + if (index->ValueType == VAL_Float /* lax */) { // DECORATE allows floats here so cast them to int. index = new FxIntCast(index); @@ -2932,7 +2932,7 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx) } else if ((*ArgList)[i]->ValueType != VAL_Int) { - if (ctx.lax && ((*ArgList)[i]->ValueType == VAL_Float)) + if ((*ArgList)[i]->ValueType == VAL_Float /* lax */) { (*ArgList)[i] = new FxIntCast((*ArgList)[i]); } @@ -3163,12 +3163,7 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) cls = PClass::FindClass(clsname); if (cls == NULL) { - if (!ctx.lax) - { - ScriptPosition.Message(MSG_ERROR,"Unknown class name '%s'", clsname.GetChars()); - delete this; - return NULL; - } + /* lax */ // Since this happens in released WADs it must pass without a terminal error... :( ScriptPosition.Message(MSG_WARNING, "Unknown class name '%s'", @@ -3341,12 +3336,8 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) destination = scope->FindState(names.Size()-1, &names[1], false); if (destination == NULL) { - ScriptPosition.Message(ctx.lax? MSG_WARNING:MSG_ERROR, "Unknown state jump destination"); - if (!ctx.lax) - { - delete this; - return NULL; - } + ScriptPosition.Message(MSG_WARNING, "Unknown state jump destination"); + /* lax */ return this; } } diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 0ac87bb35..e4923094e 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -208,7 +208,7 @@ static void ParseConstant (FScanner &sc, PSymbolTable *symt, PClassActor *cls) FxExpression *expr = ParseExpression (sc, cls); sc.MustGetToken(';'); - FCompileContext ctx(cls, true); + FCompileContext ctx(cls); expr = expr->Resolve(ctx); if (!expr->isConstant()) { @@ -266,7 +266,7 @@ static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClassActor *cls) if (sc.CheckToken('=')) { FxExpression *expr = ParseExpression (sc, cls); - FCompileContext ctx(cls, true); + FCompileContext ctx(cls); expr = expr->Resolve(ctx); if (!expr->isConstant()) { @@ -355,7 +355,7 @@ static void ParseNativeVariable (FScanner &sc, PSymbolTable *symt, PClassActor * if (sc.CheckToken('[')) { FxExpression *expr = ParseExpression (sc, cls); - FCompileContext ctx(cls, true); + FCompileContext ctx(cls); expr = expr->Resolve(ctx); if (!expr->isConstant()) { @@ -428,7 +428,7 @@ static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cl if (sc.CheckToken('[')) { FxExpression *expr = ParseExpression(sc, cls); - FCompileContext ctx(cls, true); + FCompileContext ctx(cls); int maxelems; expr = expr->Resolve(ctx); if (!expr->isConstant()) From 5cc8a9c2a7d18affeb28d7d2921ba95b32f68235 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 2 Aug 2013 21:19:05 -0500 Subject: [PATCH 112/232] Remove redundant Resolves - ParseExpression() calls Resolve() on the FxExpression before returing it, so there's no need to immediately Resolve() what it returns. --- src/thingdef/thingdef_parse.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index e4923094e..59c1bcf08 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -208,8 +208,6 @@ static void ParseConstant (FScanner &sc, PSymbolTable *symt, PClassActor *cls) FxExpression *expr = ParseExpression (sc, cls); sc.MustGetToken(';'); - FCompileContext ctx(cls); - expr = expr->Resolve(ctx); if (!expr->isConstant()) { sc.ScriptMessage("Constant definition is not a constant"); @@ -266,8 +264,6 @@ static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClassActor *cls) if (sc.CheckToken('=')) { FxExpression *expr = ParseExpression (sc, cls); - FCompileContext ctx(cls); - expr = expr->Resolve(ctx); if (!expr->isConstant()) { sc.ScriptMessage("'%s' must be constant", symname.GetChars()); @@ -355,8 +351,6 @@ static void ParseNativeVariable (FScanner &sc, PSymbolTable *symt, PClassActor * if (sc.CheckToken('[')) { FxExpression *expr = ParseExpression (sc, cls); - FCompileContext ctx(cls); - expr = expr->Resolve(ctx); if (!expr->isConstant()) { sc.ScriptError("Array size must be constant"); @@ -428,9 +422,7 @@ static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cl if (sc.CheckToken('[')) { FxExpression *expr = ParseExpression(sc, cls); - FCompileContext ctx(cls); int maxelems; - expr = expr->Resolve(ctx); if (!expr->isConstant()) { sc.ScriptMessage("Array size must be a constant"); From 11b588de4ae3e5642d9aada8ffb07de4772d410f Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 2 Aug 2013 21:54:50 -0500 Subject: [PATCH 113/232] Add names for fallback tokens. - Fixed: When falling back to the IDENTIFIER token, the identifier it would get was undefined, because it never got initialized. --- src/namedef.h | 16 +++ src/zscript/zcc-parse.lemon | 2 +- src/zscript/zcc_parser.cpp | 246 +++++++++++++++++++----------------- 3 files changed, 146 insertions(+), 118 deletions(-) diff --git a/src/namedef.h b/src/namedef.h index 96bba6a3c..1d0d95d79 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -575,3 +575,19 @@ xx(DecoCallLineSpecial) xx(DecoNameToClass) xx(DecoFindMultiNameState) xx(DecoFindSingleNameState) + +// fallback names for ZScript parser +xx(default) +xx(sbyte) +xx(byte) +xx(short) +xx(ushort) +xx(int) +xx(uint) +xx(bool) +xx(float) +xx(double) +xx(string) +xx(vector) +xx(map) +xx(array) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index 3090125aa..bb85f3016 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -435,7 +435,7 @@ vector_size(X) ::= LT INTCONST(A) GT. /* Type names can also be used as identifiers in contexts where type names * are not normally allowed. */ %fallback IDENTIFIER - SBYTE BYTE SHORT USHORT INT UINT BOOL FLOAT DOUBLE STRING VECTOR NAME. + SBYTE BYTE SHORT USHORT INT UINT BOOL FLOAT DOUBLE STRING VECTOR NAME MAP ARRAY VOID. /* Aggregate types */ %type aggregate_type {ZCC_Type *} diff --git a/src/zscript/zcc_parser.cpp b/src/zscript/zcc_parser.cpp index 3b31788db..ecf70b678 100644 --- a/src/zscript/zcc_parser.cpp +++ b/src/zscript/zcc_parser.cpp @@ -13,127 +13,138 @@ static FString ZCCTokenName(int terminal); #include "zcc-parse.h" #include "zcc-parse.c" -static TMap<SWORD, SWORD> TokenMap; +struct TokenMapEntry +{ + SWORD TokenType; + WORD TokenName; + TokenMapEntry(SWORD a, WORD b) + : TokenType(a), TokenName(b) + { } +}; +static TMap<SWORD, TokenMapEntry> TokenMap; static SWORD BackTokenMap[YYERRORSYMBOL]; // YYERRORSYMBOL immediately follows the terminals described by the grammar +#define TOKENDEF2(sc, zcc, name) { TokenMapEntry tme(zcc, name); TokenMap.Insert(sc, tme); } BackTokenMap[zcc] = sc +#define TOKENDEF(sc, zcc) TOKENDEF2(sc, zcc, NAME_None) + static void InitTokenMap() { -#define TOKENDEF(sc, zcc) TokenMap.Insert(sc, zcc); BackTokenMap[zcc] = sc - TOKENDEF('=', ZCC_EQ); - TOKENDEF(TK_MulEq, ZCC_MULEQ); - TOKENDEF(TK_DivEq, ZCC_DIVEQ); - TOKENDEF(TK_ModEq, ZCC_MODEQ); - TOKENDEF(TK_AddEq, ZCC_ADDEQ); - TOKENDEF(TK_SubEq, ZCC_SUBEQ); - TOKENDEF(TK_LShiftEq, ZCC_LSHEQ); - TOKENDEF(TK_RShiftEq, ZCC_RSHEQ); - TOKENDEF(TK_AndEq, ZCC_ANDEQ); - TOKENDEF(TK_OrEq, ZCC_OREQ); - TOKENDEF(TK_XorEq, ZCC_XOREQ); - TOKENDEF('?', ZCC_QUESTION); - TOKENDEF(':', ZCC_COLON); - TOKENDEF(TK_OrOr, ZCC_OROR); - TOKENDEF(TK_AndAnd, ZCC_ANDAND); - TOKENDEF(TK_Eq, ZCC_EQEQ); - TOKENDEF(TK_Neq, ZCC_NEQ); - TOKENDEF(TK_ApproxEq, ZCC_APPROXEQ); - TOKENDEF('<', ZCC_LT); - TOKENDEF('>', ZCC_GT); - TOKENDEF(TK_Leq, ZCC_LTEQ); - TOKENDEF(TK_Geq, ZCC_GTEQ); - TOKENDEF(TK_LtGtEq, ZCC_LTGTEQ); - TOKENDEF(TK_Is, ZCC_IS); - TOKENDEF(TK_DotDot, ZCC_DOTDOT); - TOKENDEF('|', ZCC_OR); - TOKENDEF('^', ZCC_XOR); - TOKENDEF('&', ZCC_AND); - TOKENDEF(TK_LShift, ZCC_LSH); - TOKENDEF(TK_RShift, ZCC_RSH); - TOKENDEF('-', ZCC_SUB); - TOKENDEF('+', ZCC_ADD); - TOKENDEF('*', ZCC_MUL); - TOKENDEF('/', ZCC_DIV); - TOKENDEF('%', ZCC_MOD); - TOKENDEF(TK_Cross, ZCC_CROSSPROD); - TOKENDEF(TK_Dot, ZCC_DOTPROD); - TOKENDEF(TK_MulMul, ZCC_POW); - TOKENDEF(TK_Incr, ZCC_ADDADD); - TOKENDEF(TK_Decr, ZCC_SUBSUB); - TOKENDEF('.', ZCC_DOT); - TOKENDEF('(', ZCC_LPAREN); - TOKENDEF(')', ZCC_RPAREN); - TOKENDEF(TK_ColonColon, ZCC_SCOPE); - TOKENDEF(';', ZCC_SEMICOLON); - TOKENDEF(',', ZCC_COMMA); - TOKENDEF(TK_Class, ZCC_CLASS); - TOKENDEF(TK_Abstract, ZCC_ABSTRACT); - TOKENDEF(TK_Native, ZCC_NATIVE); - TOKENDEF(TK_Replaces, ZCC_REPLACES); - TOKENDEF(TK_Static, ZCC_STATIC); - TOKENDEF(TK_Private, ZCC_PRIVATE); - TOKENDEF(TK_Protected, ZCC_PROTECTED); - TOKENDEF(TK_Latent, ZCC_LATENT); - TOKENDEF(TK_Final, ZCC_FINAL); - TOKENDEF(TK_Meta, ZCC_META); - TOKENDEF(TK_Deprecated, ZCC_DEPRECATED); - TOKENDEF(TK_ReadOnly, ZCC_READONLY); - TOKENDEF('{', ZCC_LBRACE); - TOKENDEF('}', ZCC_RBRACE); - TOKENDEF(TK_Struct, ZCC_STRUCT); - TOKENDEF(TK_Enum, ZCC_ENUM); - TOKENDEF(TK_SByte, ZCC_SBYTE); - TOKENDEF(TK_Byte, ZCC_BYTE); - TOKENDEF(TK_Short, ZCC_SHORT); - TOKENDEF(TK_UShort, ZCC_USHORT); - TOKENDEF(TK_Int, ZCC_INT); - TOKENDEF(TK_UInt, ZCC_UINT); - TOKENDEF(TK_Bool, ZCC_BOOL); - TOKENDEF(TK_Float, ZCC_FLOAT); - TOKENDEF(TK_Double, ZCC_DOUBLE); - TOKENDEF(TK_String, ZCC_STRING); - TOKENDEF(TK_Vector, ZCC_VECTOR); - TOKENDEF(TK_Name, ZCC_NAME); - TOKENDEF(TK_Map, ZCC_MAP); - TOKENDEF(TK_Array, ZCC_ARRAY); - TOKENDEF(TK_Void, ZCC_VOID); - TOKENDEF('[', ZCC_LBRACKET); - TOKENDEF(']', ZCC_RBRACKET); - TOKENDEF(TK_In, ZCC_IN); - TOKENDEF(TK_Out, ZCC_OUT); - TOKENDEF(TK_Optional, ZCC_OPTIONAL); - TOKENDEF(TK_Super, ZCC_SUPER); - TOKENDEF(TK_Self, ZCC_SELF); - TOKENDEF('~', ZCC_TILDE); - TOKENDEF('!', ZCC_BANG); - TOKENDEF(TK_SizeOf, ZCC_SIZEOF); - TOKENDEF(TK_AlignOf, ZCC_ALIGNOF); - TOKENDEF(TK_Continue, ZCC_CONTINUE); - TOKENDEF(TK_Break, ZCC_BREAK); - TOKENDEF(TK_Return, ZCC_RETURN); - TOKENDEF(TK_Do, ZCC_DO); - TOKENDEF(TK_For, ZCC_FOR); - TOKENDEF(TK_While, ZCC_WHILE); - TOKENDEF(TK_Until, ZCC_UNTIL); - TOKENDEF(TK_If, ZCC_IF); - TOKENDEF(TK_Else, ZCC_ELSE); - TOKENDEF(TK_Switch, ZCC_SWITCH); - TOKENDEF(TK_Case, ZCC_CASE); - TOKENDEF(TK_Default, ZCC_DEFAULT); - TOKENDEF(TK_Const, ZCC_CONST); - TOKENDEF(TK_Stop, ZCC_STOP); - TOKENDEF(TK_Wait, ZCC_WAIT); - TOKENDEF(TK_Fail, ZCC_FAIL); - TOKENDEF(TK_Loop, ZCC_LOOP); - TOKENDEF(TK_Goto, ZCC_GOTO); - TOKENDEF(TK_States, ZCC_STATES); + TOKENDEF ('=', ZCC_EQ); + TOKENDEF (TK_MulEq, ZCC_MULEQ); + TOKENDEF (TK_DivEq, ZCC_DIVEQ); + TOKENDEF (TK_ModEq, ZCC_MODEQ); + TOKENDEF (TK_AddEq, ZCC_ADDEQ); + TOKENDEF (TK_SubEq, ZCC_SUBEQ); + TOKENDEF (TK_LShiftEq, ZCC_LSHEQ); + TOKENDEF (TK_RShiftEq, ZCC_RSHEQ); + TOKENDEF (TK_AndEq, ZCC_ANDEQ); + TOKENDEF (TK_OrEq, ZCC_OREQ); + TOKENDEF (TK_XorEq, ZCC_XOREQ); + TOKENDEF ('?', ZCC_QUESTION); + TOKENDEF (':', ZCC_COLON); + TOKENDEF (TK_OrOr, ZCC_OROR); + TOKENDEF (TK_AndAnd, ZCC_ANDAND); + TOKENDEF (TK_Eq, ZCC_EQEQ); + TOKENDEF (TK_Neq, ZCC_NEQ); + TOKENDEF (TK_ApproxEq, ZCC_APPROXEQ); + TOKENDEF ('<', ZCC_LT); + TOKENDEF ('>', ZCC_GT); + TOKENDEF (TK_Leq, ZCC_LTEQ); + TOKENDEF (TK_Geq, ZCC_GTEQ); + TOKENDEF (TK_LtGtEq, ZCC_LTGTEQ); + TOKENDEF (TK_Is, ZCC_IS); + TOKENDEF (TK_DotDot, ZCC_DOTDOT); + TOKENDEF ('|', ZCC_OR); + TOKENDEF ('^', ZCC_XOR); + TOKENDEF ('&', ZCC_AND); + TOKENDEF (TK_LShift, ZCC_LSH); + TOKENDEF (TK_RShift, ZCC_RSH); + TOKENDEF ('-', ZCC_SUB); + TOKENDEF ('+', ZCC_ADD); + TOKENDEF ('*', ZCC_MUL); + TOKENDEF ('/', ZCC_DIV); + TOKENDEF ('%', ZCC_MOD); + TOKENDEF (TK_Cross, ZCC_CROSSPROD); + TOKENDEF (TK_Dot, ZCC_DOTPROD); + TOKENDEF (TK_MulMul, ZCC_POW); + TOKENDEF (TK_Incr, ZCC_ADDADD); + TOKENDEF (TK_Decr, ZCC_SUBSUB); + TOKENDEF ('.', ZCC_DOT); + TOKENDEF ('(', ZCC_LPAREN); + TOKENDEF (')', ZCC_RPAREN); + TOKENDEF (TK_ColonColon, ZCC_SCOPE); + TOKENDEF (';', ZCC_SEMICOLON); + TOKENDEF (',', ZCC_COMMA); + TOKENDEF (TK_Class, ZCC_CLASS); + TOKENDEF (TK_Abstract, ZCC_ABSTRACT); + TOKENDEF (TK_Native, ZCC_NATIVE); + TOKENDEF (TK_Replaces, ZCC_REPLACES); + TOKENDEF (TK_Static, ZCC_STATIC); + TOKENDEF (TK_Private, ZCC_PRIVATE); + TOKENDEF (TK_Protected, ZCC_PROTECTED); + TOKENDEF (TK_Latent, ZCC_LATENT); + TOKENDEF (TK_Final, ZCC_FINAL); + TOKENDEF (TK_Meta, ZCC_META); + TOKENDEF (TK_Deprecated, ZCC_DEPRECATED); + TOKENDEF (TK_ReadOnly, ZCC_READONLY); + TOKENDEF ('{', ZCC_LBRACE); + TOKENDEF ('}', ZCC_RBRACE); + TOKENDEF (TK_Struct, ZCC_STRUCT); + TOKENDEF (TK_Enum, ZCC_ENUM); + TOKENDEF2(TK_SByte, ZCC_SBYTE, NAME_sbyte); + TOKENDEF2(TK_Byte, ZCC_BYTE, NAME_byte); + TOKENDEF2(TK_Short, ZCC_SHORT, NAME_short); + TOKENDEF2(TK_UShort, ZCC_USHORT, NAME_ushort); + TOKENDEF2(TK_Int, ZCC_INT, NAME_int); + TOKENDEF2(TK_UInt, ZCC_UINT, NAME_uint); + TOKENDEF2(TK_Bool, ZCC_BOOL, NAME_bool); + TOKENDEF2(TK_Float, ZCC_FLOAT, NAME_float); + TOKENDEF2(TK_Double, ZCC_DOUBLE, NAME_double); + TOKENDEF2(TK_String, ZCC_STRING, NAME_string); + TOKENDEF2(TK_Vector, ZCC_VECTOR, NAME_vector); + TOKENDEF2(TK_Name, ZCC_NAME, NAME_Name); + TOKENDEF2(TK_Map, ZCC_MAP, NAME_map); + TOKENDEF2(TK_Array, ZCC_ARRAY, NAME_array); + TOKENDEF (TK_Void, ZCC_VOID); + TOKENDEF ('[', ZCC_LBRACKET); + TOKENDEF (']', ZCC_RBRACKET); + TOKENDEF (TK_In, ZCC_IN); + TOKENDEF (TK_Out, ZCC_OUT); + TOKENDEF (TK_Optional, ZCC_OPTIONAL); + TOKENDEF (TK_Super, ZCC_SUPER); + TOKENDEF (TK_Self, ZCC_SELF); + TOKENDEF ('~', ZCC_TILDE); + TOKENDEF ('!', ZCC_BANG); + TOKENDEF (TK_SizeOf, ZCC_SIZEOF); + TOKENDEF (TK_AlignOf, ZCC_ALIGNOF); + TOKENDEF (TK_Continue, ZCC_CONTINUE); + TOKENDEF (TK_Break, ZCC_BREAK); + TOKENDEF (TK_Return, ZCC_RETURN); + TOKENDEF (TK_Do, ZCC_DO); + TOKENDEF (TK_For, ZCC_FOR); + TOKENDEF (TK_While, ZCC_WHILE); + TOKENDEF (TK_Until, ZCC_UNTIL); + TOKENDEF (TK_If, ZCC_IF); + TOKENDEF (TK_Else, ZCC_ELSE); + TOKENDEF (TK_Switch, ZCC_SWITCH); + TOKENDEF (TK_Case, ZCC_CASE); + TOKENDEF2(TK_Default, ZCC_DEFAULT, NAME_default); + TOKENDEF (TK_Const, ZCC_CONST); + TOKENDEF (TK_Stop, ZCC_STOP); + TOKENDEF (TK_Wait, ZCC_WAIT); + TOKENDEF (TK_Fail, ZCC_FAIL); + TOKENDEF (TK_Loop, ZCC_LOOP); + TOKENDEF (TK_Goto, ZCC_GOTO); + TOKENDEF (TK_States, ZCC_STATES); - TOKENDEF(TK_Identifier, ZCC_IDENTIFIER); - TOKENDEF(TK_StringConst, ZCC_STRCONST); - TOKENDEF(TK_IntConst, ZCC_INTCONST); - TOKENDEF(TK_FloatConst, ZCC_FLOATCONST); - TOKENDEF(TK_NonWhitespace, ZCC_NWS); -#undef TOKENDEF + TOKENDEF (TK_Identifier, ZCC_IDENTIFIER); + TOKENDEF (TK_StringConst, ZCC_STRCONST); + TOKENDEF (TK_IntConst, ZCC_INTCONST); + TOKENDEF (TK_FloatConst, ZCC_FLOATCONST); + TOKENDEF (TK_NonWhitespace, ZCC_NWS); } +#undef TOKENDEF +#undef TOKENDEF2 static void DoParse(const char *filename) { @@ -202,10 +213,11 @@ static void DoParse(const char *filename) } else { - SWORD *zcctoken = TokenMap.CheckKey(sc.TokenType); + TokenMapEntry *zcctoken = TokenMap.CheckKey(sc.TokenType); if (zcctoken != NULL) { - tokentype = *zcctoken; + tokentype = zcctoken->TokenType; + value.Int = zcctoken->TokenName; } else { From 91207ed3f400e34f7ff7377b3714c5e2468a00f8 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 2 Aug 2013 21:57:12 -0500 Subject: [PATCH 114/232] Update lemon.c to August 2012 version from SQLite. - Add a missing check for out-of-memory in the lemon code generator. - Fix a total unimportant file descriptor leak in lemon. This is to silence warning messages. - Fix a bug in lemon in computation of which non-terminals can generate an empty string. This bug and the fix make absolutely no difference for the grammar used by SQLite, but it can make a difference when lemon is used in other grammars. - In Lemon, when comparing the output to the *.h file to see if it has changed, make sure that the proposed new output and the preexisting output are the same size before deciding that they are the same. --- tools/lemon/lemon.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tools/lemon/lemon.c b/tools/lemon/lemon.c index 7fd95eb2d..b544128cb 100644 --- a/tools/lemon/lemon.c +++ b/tools/lemon/lemon.c @@ -632,7 +632,8 @@ struct lemon *lemp; if( rp->lhs->lambda ) continue; for(i=0; i<rp->nrhs; i++){ struct symbol *sp = rp->rhs[i]; - if( sp->type!=TERMINAL || sp->lambda==LEMON_FALSE ) break; + assert( sp->type==NONTERMINAL || sp->lambda==LEMON_FALSE ); + if( sp->lambda==LEMON_FALSE ) break; } if( i==rp->nrhs ){ rp->lhs->lambda = LEMON_TRUE; @@ -2549,6 +2550,7 @@ struct lemon *gp; ErrorMsg(ps.filename,0,"Can't allocate %d of memory to hold this file.", filesize+1); gp->errorcnt++; + fclose(fp); return; } if( fread(filebuf,1,filesize,fp)!=filesize ){ @@ -2556,6 +2558,7 @@ struct lemon *gp; filesize); free(filebuf); gp->errorcnt++; + fclose(fp); return; } fclose(fp); @@ -3421,6 +3424,10 @@ int mhflag; /* True if generating makeheaders output */ /* Allocate and initialize types[] and allocate stddt[] */ arraysize = lemp->nsymbol * 2; types = (char**)calloc( arraysize, sizeof(char*) ); + if( types==0 ){ + fprintf(stderr,"Out of memory.\n"); + exit(1); + } maxdtlength = 0; if( lemp->vartype ){ maxdtlength = lemonStrlen(lemp->vartype); @@ -4028,12 +4035,14 @@ struct lemon *lemp; else prefix = ""; in = file_open(lemp,".h","rb"); if( in ){ + int nextChar; for(i=1; i<lemp->nterminal && fgets(line,LINESIZE,in); i++){ sprintf(pattern,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i); if( strcmp(line,pattern) ) break; } + nextChar = fgetc(in); fclose(in); - if( i==lemp->nterminal ){ + if( i==lemp->nterminal && nextChar==EOF ){ /* No change in the file. Don't rewrite it. */ /* (not the best idea if you use make tools that check the date! */ /*return;*/ From dbaf72772b898059e5fa3de3694680483c97dd7e Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 7 Aug 2013 19:38:42 -0500 Subject: [PATCH 115/232] Move the symbol table from PClass to PStruct. --- src/dobjtype.cpp | 23 +++++------------------ src/dobjtype.h | 3 +-- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 9420a939f..7f6d24352 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -864,8 +864,12 @@ IMPLEMENT_CLASS(PStruct) size_t PStruct::PropagateMark() { + size_t marked; + GC::MarkArray(Fields); - return Fields.Size() * sizeof(void*) + Super::PropagateMark(); + marked = Fields.Size() * sizeof(void*); + marked += Symbols.MarkSymbols(); + return marked + Super::PropagateMark(); } /* PPrototype *************************************************************/ @@ -1081,7 +1085,6 @@ PClass::PClass() PClass::~PClass() { - Symbols.ReleaseSymbols(); if (Defaults != NULL) { M_Free(Defaults); @@ -1431,22 +1434,6 @@ const PClass *PClass::NativeClass() const return cls; } -//========================================================================== -// -// PClass :: PropagateMark -// -//========================================================================== - -size_t PClass::PropagateMark() -{ - size_t marked; - - // Mark symbols - marked = Symbols.MarkSymbols(); - - return marked + Super::PropagateMark(); -} - /* FTypeTable **************************************************************/ //========================================================================== diff --git a/src/dobjtype.h b/src/dobjtype.h index b245611bc..535b113ac 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -408,6 +408,7 @@ class PStruct : public PNamedType DECLARE_CLASS(PStruct, PNamedType); public: TArray<PField *> Fields; + PSymbolTable Symbols; size_t PropagateMark(); }; @@ -464,7 +465,6 @@ public: const size_t *FlatPointers; // object pointers defined by this class and all its superclasses; not initialized by default BYTE *Defaults; bool bRuntimeClass; // class was defined at run-time, not compile-time - PSymbolTable Symbols; void (*ConstructNative)(void *); @@ -478,7 +478,6 @@ public: void InitializeActorInfo(); void BuildFlatPointers(); const PClass *NativeClass() const; - size_t PropagateMark(); // Returns true if this type is an ancestor of (or same as) the passed type. bool IsAncestorOf(const PClass *ti) const From 12a312b6b498f7d03213d15906d04ac5f500138a Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 7 Aug 2013 20:04:05 -0500 Subject: [PATCH 116/232] - Fixed: NewArray returned the element type, not the array type. --- src/dobjtype.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 7f6d24352..fd856bca3 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -640,9 +640,9 @@ PArray *NewArray(PType *type, unsigned int count) if (atype == NULL) { atype = new PArray(type, count); - TypeTable.AddType(type, RUNTIME_CLASS(PArray), (intptr_t)type, count, bucket); + TypeTable.AddType(atype, RUNTIME_CLASS(PArray), (intptr_t)type, count, bucket); } - return (PArray *)type; + return (PArray *)atype; } /* PVector ****************************************************************/ From 0ec33191aa39a999f34b2eaab5e200230d050621 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 7 Aug 2013 20:13:48 -0500 Subject: [PATCH 117/232] - Added NewEnum() function. --- src/dobjtype.cpp | 43 +++++++++++++++++++++++++++++++++++++++++++ src/dobjtype.h | 6 ++++++ 2 files changed, 49 insertions(+) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index fd856bca3..bcc68931f 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -568,6 +568,49 @@ IMPLEMENT_POINTY_CLASS(PEnum) DECLARE_POINTER(ValueType) END_POINTERS +//========================================================================== +// +// PEnum - Default Constructor +// +//========================================================================== + +PEnum::PEnum() +: ValueType(NULL) +{ +} + +//========================================================================== +// +// PEnum - Parameterized Constructor +// +//========================================================================== + +PEnum::PEnum(FName name, DObject *outer) +: PNamedType(name, outer), ValueType(NULL) +{ +} + +//========================================================================== +// +// NewEnum +// +// Returns a PEnum for the given name and container, making sure not to +// create duplicates. +// +//========================================================================== + +PEnum *NewEnum(FName name, DObject *outer) +{ + size_t bucket; + PType *etype = TypeTable.FindType(RUNTIME_CLASS(PEnum), (intptr_t)outer, (intptr_t)name, &bucket); + if (etype == NULL) + { + etype = new PEnum(name, outer); + TypeTable.AddType(etype, RUNTIME_CLASS(PEnum), (intptr_t)outer, (intptr_t)name, bucket); + } + return static_cast<PEnum *>(etype); +} + /* PArray *****************************************************************/ IMPLEMENT_POINTY_CLASS(PArray) diff --git a/src/dobjtype.h b/src/dobjtype.h index 535b113ac..68ed6168d 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -224,6 +224,7 @@ public: FName TypeName; // this type's name PNamedType() : Outer(NULL) {} + PNamedType(FName name, DObject *outer) : Outer(outer), TypeName(name) {} virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; @@ -341,8 +342,12 @@ class PEnum : public PNamedType DECLARE_CLASS(PEnum, PNamedType); HAS_OBJECT_POINTERS; public: + PEnum(FName name, DObject *outer); + PType *ValueType; TMap<FName, int> Values; +protected: + PEnum(); }; class PArray : public PCompoundType @@ -579,6 +584,7 @@ PDynArray *NewDynArray(PType *type); PPointer *NewPointer(PType *type); PClassPointer *NewClassPointer(PClass *restrict); PClassWaitingForParent *NewUnknownClass(FName myname, FName parentname); +PEnum *NewEnum(FName name, DObject *outer); // Built-in types ----------------------------------------------------------- From 7e24f6b00c0bc4df12ce03ac2b5672f5914d10ed Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 7 Aug 2013 20:14:27 -0500 Subject: [PATCH 118/232] - Added NewStruct() function. --- src/dobjtype.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ src/dobjtype.h | 5 +++++ 2 files changed, 46 insertions(+) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index bcc68931f..e9892ea2e 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -899,6 +899,27 @@ PMap *NewMap(PType *keytype, PType *valuetype) IMPLEMENT_CLASS(PStruct) +//========================================================================== +// +// PStruct - Default Constructor +// +//========================================================================== + +PStruct::PStruct() +{ +} + +//========================================================================== +// +// PStruct - Parameterized Constructor +// +//========================================================================== + +PStruct::PStruct(FName name, DObject *outer) +: PNamedType(name, outer) +{ +} + //========================================================================== // // PStruct :: PropagateMark @@ -915,6 +936,26 @@ size_t PStruct::PropagateMark() return marked + Super::PropagateMark(); } +//========================================================================== +// +// NewStruct +// Returns a PStruct for the given name and container, making sure not to +// create duplicates. +// +//========================================================================== + +PStruct *NewStruct(FName name, DObject *outer) +{ + size_t bucket; + PType *stype = TypeTable.FindType(RUNTIME_CLASS(PStruct), (intptr_t)outer, (intptr_t)name, &bucket); + if (stype == NULL) + { + stype = new PStruct(name, outer); + TypeTable.AddType(stype, RUNTIME_CLASS(PStruct), (intptr_t)outer, (intptr_t)name, bucket); + } + return static_cast<PStruct *>(stype); +} + /* PPrototype *************************************************************/ IMPLEMENT_CLASS(PPrototype) diff --git a/src/dobjtype.h b/src/dobjtype.h index 68ed6168d..25e81ceb5 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -412,10 +412,14 @@ class PStruct : public PNamedType { DECLARE_CLASS(PStruct, PNamedType); public: + PStruct(FName name, DObject *outer); + TArray<PField *> Fields; PSymbolTable Symbols; size_t PropagateMark(); +protected: + PStruct(); }; class PPrototype : public PCompoundType @@ -585,6 +589,7 @@ PPointer *NewPointer(PType *type); PClassPointer *NewClassPointer(PClass *restrict); PClassWaitingForParent *NewUnknownClass(FName myname, FName parentname); PEnum *NewEnum(FName name, DObject *outer); +PStruct *NewStruct(FName name, DObject *outer); // Built-in types ----------------------------------------------------------- From 476a98652c622f1a8c7839bc6302a9b7a9b321cc Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 7 Aug 2013 20:22:01 -0500 Subject: [PATCH 119/232] Remove extraneous PField class - Remove the existing PField class, rename PMemberField to PField, and derive it from PSymbol instead of the old PField. --- src/dobjtype.h | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/dobjtype.h b/src/dobjtype.h index 25e81ceb5..91b5ae269 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -319,16 +319,10 @@ protected: // Struct/class fields ------------------------------------------------------ -class PField : public DObject +// A PField describes a symbol that takes up physical space in the struct. +class PField : public PSymbol { - DECLARE_ABSTRACT_CLASS(PField, DObject); -public: - FName FieldName; -}; - -class PMemberField : public PField -{ - DECLARE_CLASS(PMemberField, PField); + DECLARE_CLASS(PField, PSymbol); HAS_OBJECT_POINTERS public: unsigned int FieldOffset; From 6c1f3a139616613ddb0824df04e6f7e1f5a52275 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Thu, 8 Aug 2013 22:16:13 -0500 Subject: [PATCH 120/232] Added PStruct::AddField() --- src/dobjtype.cpp | 28 ++++++++++++++++++++++++++++ src/dobjtype.h | 4 ++++ 2 files changed, 32 insertions(+) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index e9892ea2e..66ee86f5a 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -920,6 +920,34 @@ PStruct::PStruct(FName name, DObject *outer) { } +//========================================================================== +// +// PStruct :: AddField +// +// Appends a new field to the end of a struct. +// +//========================================================================== + +PField *PStruct::AddField(FName name, PType *type) +{ + PField *field = new PField(name, type); + + // The new field is added to the end of this struct, alignment permitting. + field->FieldOffset = (Size + (type->Align - 1)) & ~(type->Align - 1); + + // Enlarge this struct to enclose the new field. + Size = field->FieldOffset + type->Size; + + // This struct's alignment is the same as the largest alignment of any of + // its fields. + Align = MAX(Align, type->Align); + + Fields.Push(field); + Symbols.AddSymbol(field); + + return field; +} + //========================================================================== // // PStruct :: PropagateMark diff --git a/src/dobjtype.h b/src/dobjtype.h index 91b5ae269..4e867c102 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -325,6 +325,8 @@ class PField : public PSymbol DECLARE_CLASS(PField, PSymbol); HAS_OBJECT_POINTERS public: + PField(FName name, PType *type) : PSymbol(name), FieldOffset(0), FieldType(type) {} + unsigned int FieldOffset; PType *FieldType; }; @@ -411,6 +413,8 @@ public: TArray<PField *> Fields; PSymbolTable Symbols; + PField *AddField(FName name, PType *type); + size_t PropagateMark(); protected: PStruct(); From 93cbdd37a5a02c145c90aeb88814fb777f45f9f8 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Thu, 8 Aug 2013 22:20:16 -0500 Subject: [PATCH 121/232] PArray's size should take alignment into account. --- src/dobjtype.cpp | 5 ++++- src/dobjtype.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 66ee86f5a..f8a4a8c88 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -638,7 +638,10 @@ PArray::PArray(PType *etype, unsigned int ecount) : ElementType(etype), ElementCount(ecount) { Align = etype->Align; - Size = etype->Size * ecount; + // Since we are concatenating elements together, the element size should + // also be padded to the nearest alignment. + ElementSize = (etype->Size + (etype->Align - 1)) & ~(etype->Align - 1); + Size = ElementSize * ecount; } //========================================================================== diff --git a/src/dobjtype.h b/src/dobjtype.h index 4e867c102..01653c847 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -355,6 +355,7 @@ public: PType *ElementType; unsigned int ElementCount; + unsigned int ElementSize; virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; From f18c7b8959a93af4ffbb260a2a3e676090de8aea Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 9 Aug 2013 22:41:36 -0500 Subject: [PATCH 122/232] Make FType::Hash work for PPrototype - For Prototypes, Hash is passed the address of two TArrays. If we blindly hash those without checking their contents, then we can forget about ever finding any matching prototypes in the type table. (Not that I remember why I wanted them to be unique, but I'm sure I must have had my reasons.) --- src/dobjtype.cpp | 25 +++++++++++++++++++++---- src/dobjtype.h | 2 +- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index f8a4a8c88..92e37333a 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -1646,17 +1646,34 @@ void FTypeTable::AddType(PType *type) // //========================================================================== -size_t FTypeTable::Hash(const void *p1, intptr_t p2, intptr_t p3) +size_t FTypeTable::Hash(const PClass *p1, intptr_t p2, intptr_t p3) { size_t i1 = (size_t)p1; - size_t i2 = (size_t)p2; - size_t i3 = (size_t)p3; // Swap the high and low halves of i1. The compiler should be smart enough // to transform this into a ROR or ROL. i1 = (i1 >> (sizeof(size_t)*4)) | (i1 << (sizeof(size_t)*4)); - return (~i1 ^ i2) + i3 * 961748927; // i3 is multiplied by a prime + if (p1 != RUNTIME_CLASS(PPrototype)) + { + size_t i2 = (size_t)p2; + size_t i3 = (size_t)p3; + return (~i1 ^ i2) + i3 * 961748927; // i3 is multiplied by a prime + } + else + { // Prototypes need to hash the TArrays at p2 and p3 + const TArray<PType *> *a2 = (const TArray<PType *> *)p2; + const TArray<PType *> *a3 = (const TArray<PType *> *)p3; + for (unsigned i = 0; i < a2->Size(); ++i) + { + i1 = (i1 * 961748927) + (size_t)((*a2)[i]); + } + for (unsigned i = 0; i < a3->Size(); ++i) + { + i1 = (i1 * 961748927) + (size_t)((*a3)[i]); + } + return i1; + } } //========================================================================== diff --git a/src/dobjtype.h b/src/dobjtype.h index 01653c847..e3fb2603a 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -573,7 +573,7 @@ struct FTypeTable void Mark(); void Clear(); - static size_t Hash(const void *p1, intptr_t p2, intptr_t p3); + static size_t Hash(const PClass *p1, intptr_t p2, intptr_t p3); }; From 3e46e6376c5481256226a256cf31e262a3f19b14 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 9 Aug 2013 22:48:02 -0500 Subject: [PATCH 123/232] Added NewPrototype() function --- src/dobjtype.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ src/dobjtype.h | 5 +++++ 2 files changed, 47 insertions(+) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 92e37333a..45dc4ee48 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -991,6 +991,27 @@ PStruct *NewStruct(FName name, DObject *outer) IMPLEMENT_CLASS(PPrototype) +//========================================================================== +// +// PPrototype - Default Constructor +// +//========================================================================== + +PPrototype::PPrototype() +{ +} + +//========================================================================== +// +// PPrototype - Parameterized Constructor +// +//========================================================================== + +PPrototype::PPrototype(const TArray<PType *> &rettypes, const TArray<PType *> &argtypes) +: ArgumentTypes(argtypes), ReturnTypes(rettypes) +{ +} + //========================================================================== // // PPrototype :: IsMatch @@ -1031,6 +1052,27 @@ size_t PPrototype::PropagateMark() Super::PropagateMark(); } +//========================================================================== +// +// NewPrototype +// +// Returns a PPrototype for the given return and argument types, making sure +// not to create duplicates. +// +//========================================================================== + +PPrototype *NewPrototype(const TArray<PType *> &rettypes, const TArray<PType *> &argtypes) +{ + size_t bucket; + PType *proto = TypeTable.FindType(RUNTIME_CLASS(PPrototype), (intptr_t)&argtypes, (intptr_t)&rettypes, &bucket); + if (proto == NULL) + { + proto = new PPrototype(rettypes, argtypes); + TypeTable.AddType(proto, RUNTIME_CLASS(PPrototype), (intptr_t)&argtypes, (intptr_t)&rettypes, bucket); + } + return static_cast<PPrototype *>(proto); +} + /* PFunction **************************************************************/ IMPLEMENT_CLASS(PFunction) diff --git a/src/dobjtype.h b/src/dobjtype.h index e3fb2603a..a927a3298 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -425,12 +425,16 @@ class PPrototype : public PCompoundType { DECLARE_CLASS(PPrototype, PCompoundType); public: + PPrototype(const TArray<PType *> &rettypes, const TArray<PType *> &argtypes); + TArray<PType *> ArgumentTypes; TArray<PType *> ReturnTypes; size_t PropagateMark(); virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; +protected: + PPrototype(); }; // TBD: Should we really support overloading? @@ -589,6 +593,7 @@ PClassPointer *NewClassPointer(PClass *restrict); PClassWaitingForParent *NewUnknownClass(FName myname, FName parentname); PEnum *NewEnum(FName name, DObject *outer); PStruct *NewStruct(FName name, DObject *outer); +PPrototype *NewPrototype(const TArray<PType *> &rettypes, const TArray<PType *> &argtypes); // Built-in types ----------------------------------------------------------- From 6575499f37167f9b76f474762fa93370ec9e606a Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 10 Aug 2013 20:17:29 -0500 Subject: [PATCH 124/232] Added basic implementation for PField. - I don't know why this didn't give me trouble before, but I needed to add IMPLEMENT_CLASS for PField. --- src/dobjtype.cpp | 15 +++++++++++++++ src/dobjtype.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 45dc4ee48..c54931a16 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -987,6 +987,21 @@ PStruct *NewStruct(FName name, DObject *outer) return static_cast<PStruct *>(stype); } +/* PField *****************************************************************/ + +IMPLEMENT_CLASS(PField) + +//========================================================================== +// +// PField - Default Constructor +// +//========================================================================== + +PField::PField() +: PSymbol(NAME_None) +{ +} + /* PPrototype *************************************************************/ IMPLEMENT_CLASS(PPrototype) diff --git a/src/dobjtype.h b/src/dobjtype.h index a927a3298..a6f3bd843 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -329,6 +329,8 @@ public: unsigned int FieldOffset; PType *FieldType; +protected: + PField(); }; // Compound types ----------------------------------------------------------- From 973b0f5c5648dbbab365b1c39357e8c36e286759 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 10 Aug 2013 20:17:55 -0500 Subject: [PATCH 125/232] Change PFunction's superclass from PNamedType to PSymbol --- src/dobjtype.cpp | 1 - src/dobjtype.h | 7 +++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index c54931a16..c981a00e9 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -253,7 +253,6 @@ void PType::StaticInit() RUNTIME_CLASS(PMap)->TypeTableType = RUNTIME_CLASS(PMap); RUNTIME_CLASS(PStruct)->TypeTableType = RUNTIME_CLASS(PStruct); RUNTIME_CLASS(PPrototype)->TypeTableType = RUNTIME_CLASS(PPrototype); - RUNTIME_CLASS(PFunction)->TypeTableType = RUNTIME_CLASS(PFunction); RUNTIME_CLASS(PClass)->TypeTableType = RUNTIME_CLASS(PClass); TypeTable.AddType(TypeSInt8 = new PInt(1, false)); diff --git a/src/dobjtype.h b/src/dobjtype.h index a6f3bd843..c9ba10f39 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -440,9 +440,9 @@ protected: }; // TBD: Should we really support overloading? -class PFunction : public PNamedType +class PFunction : public PSymbol { - DECLARE_CLASS(PFunction, PNamedType); + DECLARE_CLASS(PFunction, PSymbol); public: struct Variant { @@ -452,6 +452,9 @@ public: TArray<Variant> Variants; size_t PropagateMark(); + + PFunction(FName name) : PSymbol(name) {} + PFunction() : PSymbol(NAME_None) {} }; // Meta-info for every class derived from DObject --------------------------- From 55bec365e8a76027627faf34abfc0988cc9c33df Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 10 Aug 2013 20:24:12 -0500 Subject: [PATCH 126/232] Added a way to specify paramater flags for PFunction - And right now, the only flag is "Optional". --- src/dobjtype.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/dobjtype.h b/src/dobjtype.h index c9ba10f39..67e3f5f4f 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -8,6 +8,13 @@ #include "thingdef/thingdef_type.h" #include "vm.h" +// Variable/parameter/field flags ------------------------------------------- + +// Making all these different storage types use a common set of flags seems +// like the simplest thing to do. + +#define VARF_Optional (1<<0) // func param is optional + // Symbol information ------------------------------------------------------- class PSymbol : public DObject @@ -448,6 +455,7 @@ public: { PPrototype *Proto; VMFunction *Implementation; + TArray<DWORD> ArgFlags; // Should be the same length as Proto->ArgumentTypes }; TArray<Variant> Variants; From ed1c22186f9e1e1e440e3cd9a43997f7d86faa5b Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 14 Aug 2013 21:53:03 -0500 Subject: [PATCH 127/232] Add PStatePointer type --- src/dobjtype.cpp | 19 +++++++++++++++++++ src/dobjtype.h | 8 ++++++++ 2 files changed, 27 insertions(+) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index c981a00e9..190f92597 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -69,6 +69,7 @@ PString *TypeString; PName *TypeName; PSound *TypeSound; PColor *TypeColor; +PStatePointer *TypeState; // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -267,6 +268,7 @@ void PType::StaticInit() TypeTable.AddType(TypeName = new PName); TypeTable.AddType(TypeSound = new PSound); TypeTable.AddType(TypeColor = new PColor); + TypeTable.AddType(TypeState = new PStatePointer); } @@ -447,6 +449,23 @@ PColor::PColor() assert(sizeof(PalEntry) == __alignof(PalEntry)); } +/* PStatePointer **********************************************************/ + +IMPLEMENT_CLASS(PStatePointer) + +//========================================================================== +// +// PStatePointer Default Constructor +// +//========================================================================== + +PStatePointer::PStatePointer() +: PInt(sizeof(FState *), true) +{ + Align = __alignof(FState *); +} + + /* PPointer ***************************************************************/ IMPLEMENT_POINTY_CLASS(PPointer) diff --git a/src/dobjtype.h b/src/dobjtype.h index 67e3f5f4f..edaaae4f2 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -291,6 +291,13 @@ public: // Pointers ----------------------------------------------------------------- +class PStatePointer : public PInt +{ + DECLARE_CLASS(PStatePointer, PInt); +public: + PStatePointer(); +}; + class PPointer : public PInt { DECLARE_CLASS(PPointer, PInt); @@ -618,5 +625,6 @@ extern PString *TypeString; extern PName *TypeName; extern PSound *TypeSound; extern PColor *TypeColor; +extern PStatePointer *TypeState; #endif From 8fbb4b90fbc06104f32e39083528601a5f6c7fcf Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 14 Aug 2013 21:56:21 -0500 Subject: [PATCH 128/232] Add some flags for PFunction --- src/dobjtype.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/dobjtype.h b/src/dobjtype.h index edaaae4f2..6223d2cdf 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -13,7 +13,9 @@ // Making all these different storage types use a common set of flags seems // like the simplest thing to do. -#define VARF_Optional (1<<0) // func param is optional +#define VARF_Optional (1<<0) // func param is optional +#define VARF_Method (1<<1) // func has an implied self parameter +#define VARF_Action (1<<2) // func has implied owner and state parameters // Symbol information ------------------------------------------------------- @@ -465,11 +467,13 @@ public: TArray<DWORD> ArgFlags; // Should be the same length as Proto->ArgumentTypes }; TArray<Variant> Variants; + DWORD Flags; + size_t PropagateMark(); - PFunction(FName name) : PSymbol(name) {} - PFunction() : PSymbol(NAME_None) {} + PFunction(FName name) : PSymbol(name), Flags(0) {} + PFunction() : PSymbol(NAME_None), Flags(0) {} }; // Meta-info for every class derived from DObject --------------------------- From aba691ad721a55c08edc2f76ab985bcf2fb14f66 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 14 Aug 2013 21:59:10 -0500 Subject: [PATCH 129/232] Implement NewClassPointer() --- src/dobjtype.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 190f92597..443fd35b7 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -579,6 +579,25 @@ void PClassPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const id2 = (intptr_t)ClassRestriction; } +//========================================================================== +// +// NewClassPointer +// +// Returns a PClassPointer for the restricted type. +// +//========================================================================== + +PClassPointer *NewClassPointer(PClass *restrict) +{ + size_t bucket; + PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PPointer), (intptr_t)RUNTIME_CLASS(PClass), (intptr_t)restrict, &bucket); + if (ptype == NULL) + { + ptype = new PClassPointer(restrict); + TypeTable.AddType(ptype, RUNTIME_CLASS(PPointer), (intptr_t)RUNTIME_CLASS(PClass), (intptr_t)restrict, bucket); + } + return static_cast<PClassPointer *>(ptype); +} /* PEnum ******************************************************************/ From cf87d0f1e9a1e879698d7975409125253a44b51a Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 14 Aug 2013 22:00:16 -0500 Subject: [PATCH 130/232] Use PFunction instead of PSymbolActionFunction in DECORATE parser --- src/d_dehacked.cpp | 24 ++-- src/dobjtype.cpp | 22 +++- src/dobjtype.h | 31 +----- src/thingdef/olddecorations.cpp | 18 +-- src/thingdef/thingdef.h | 4 +- src/thingdef/thingdef_data.cpp | 4 +- src/thingdef/thingdef_parse.cpp | 185 +++++++++++++++---------------- src/thingdef/thingdef_states.cpp | 53 +++++---- 8 files changed, 169 insertions(+), 172 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index d0ba97237..a375b3435 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -81,7 +81,7 @@ static void UnloadDehSupp (); // This is a list of all the action functions used by each of Doom's states. -static TArray<PSymbolActionFunction *> Actions; +static TArray<PFunction *> Actions; // These are the original heights of every Doom 2 thing. They are used if a patch // specifies that a thing should be hanging from the ceiling but doesn't specify @@ -788,8 +788,8 @@ void SetDehParams(FState *state, int codepointer) FScriptPosition *pos = new FScriptPosition(FString("DEHACKED"), 0); // Let's identify the codepointer we're dealing with. - PSymbolActionFunction *sym; - sym = dyn_cast<PSymbolActionFunction>(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(FName(MBFCodePointers[codepointer].name), true)); + PFunction *sym; + sym = dyn_cast<PFunction>(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(FName(MBFCodePointers[codepointer].name), true)); if (sym == NULL) return; if (codepointer < 0 || codepointer >= countof(MBFCodePointerFactories)) @@ -809,7 +809,7 @@ void SetDehParams(FState *state, int codepointer) buildit.Emit(OP_PARAM, 0, REGT_POINTER, 2); // Emit code for action parameters. int argcount = MBFCodePointerFactories[codepointer](buildit, value1, value2); - buildit.Emit(OP_TAIL_K, buildit.GetConstantAddress(sym->Function, ATAG_OBJECT), NAP + argcount, 0); + buildit.Emit(OP_TAIL_K, buildit.GetConstantAddress(sym->Variants[0].Implementation, ATAG_OBJECT), NAP + argcount, 0); // Attach it to the state. VMScriptFunction *sfunc = buildit.MakeFunction(); sfunc->NumArgs = NAP; @@ -1711,7 +1711,7 @@ static int PatchWeapon (int weapNum) return result; } -static void SetPointer(FState *state, PSymbolActionFunction *sym, int frame = 0) +static void SetPointer(FState *state, PFunction *sym, int frame = 0) { if (sym == NULL) { @@ -1720,7 +1720,7 @@ static void SetPointer(FState *state, PSymbolActionFunction *sym, int frame = 0) } else { - state->SetAction(sym->Function); + state->SetAction(sym->Variants[0].Implementation); for (unsigned int i = 0; i < MBFCodePointers.Size(); i++) { @@ -2103,15 +2103,15 @@ static int PatchCodePtrs (int dummy) // This skips the action table and goes directly to the internal symbol table // DEH compatible functions are easy to recognize. - PSymbolActionFunction *sym = dyn_cast<PSymbolActionFunction>(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(symname, true)); + PFunction *sym = dyn_cast<PFunction>(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(symname, true)); if (sym == NULL) { Printf("Frame %d: Unknown code pointer '%s'\n", frame, Line2); } else { - FString &args = sym->Arguments; - if (args.Len() != 0 && (args[0] < 'a' || args[0] > 'z')) + TArray<DWORD> &args = sym->Variants[0].ArgFlags; + if (args.Size() != 0 && !(args[0] & VARF_Optional)) { Printf("Frame %d: Incompatible code pointer '%s'\n", frame, Line2); sym = NULL; @@ -2680,15 +2680,15 @@ static bool LoadDehSupp () // or AActor so this will find all of them. FString name = "A_"; name << sc.String; - PSymbolActionFunction *sym = dyn_cast<PSymbolActionFunction>(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(name, true)); + PFunction *sym = dyn_cast<PFunction>(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(name, true)); if (sym == NULL) { sc.ScriptError("Unknown code pointer '%s'", sc.String); } else { - FString &args = sym->Arguments; - if (args.Len() != 0 && (args[0] < 'a' || args[0] > 'z')) + TArray<DWORD> &args = sym->Variants[0].ArgFlags; + if (args.Size() != 0 && !(args[0] & VARF_Optional)) { sc.ScriptError("Incompatible code pointer '%s'", sc.String); } diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 443fd35b7..68e5e8b31 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -1145,6 +1145,25 @@ size_t PFunction::PropagateMark() return Variants.Size() * sizeof(Variants[0]) + Super::PropagateMark(); } +//========================================================================== +// +// PFunction :: AddVariant +// +// Adds a new variant for this function. Does not check if a matching +// variant already exists. +// +//========================================================================== + +unsigned PFunction::AddVariant(PPrototype *proto, TArray<DWORD> &argflags, VMFunction *impl) +{ + Variant variant; + + variant.Proto = proto; + variant.ArgFlags = argflags; + variant.Implementation = impl; + return Variants.Push(variant); +} + /* PClass *****************************************************************/ IMPLEMENT_POINTY_CLASS(PClass) @@ -1814,9 +1833,6 @@ CCMD(typetable) IMPLEMENT_ABSTRACT_CLASS(PSymbol); IMPLEMENT_CLASS(PSymbolConst); IMPLEMENT_CLASS(PSymbolVariable); -IMPLEMENT_POINTY_CLASS(PSymbolActionFunction) - DECLARE_POINTER(Function) -END_POINTERS IMPLEMENT_POINTY_CLASS(PSymbolVMFunction) DECLARE_POINTER(Function) END_POINTERS diff --git a/src/dobjtype.h b/src/dobjtype.h index 6223d2cdf..17748b13b 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -64,23 +64,7 @@ public: }; // An action function ------------------------------------------------------- -// -// The Arguments string is a string of characters as understood by -// the DECORATE parser: -// -// If the letter is uppercase, it is required. Lowercase letters are optional. -// i = integer -// f = fixed point -// s = sound name -// m = actor name -// t = string -// l = jump label -// c = color -// x = expression -// y = expression -// If the final character is a +, the previous parameter is repeated indefinitely, -// and an "imaginary" first parameter is inserted containing the total number of -// parameters passed. + struct FState; struct StateCallData; class VMFrameStack; @@ -89,18 +73,6 @@ struct VMReturn; typedef int (*actionf_p)(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret);/*(VM_ARGS)*/ class VMFunction; -class PSymbolActionFunction : public PSymbol -{ - DECLARE_CLASS(PSymbolActionFunction, PSymbol); - HAS_OBJECT_POINTERS; -public: - FString Arguments; - VMFunction *Function; - - PSymbolActionFunction(FName name) : PSymbol(name) {} - PSymbolActionFunction() : PSymbol(NAME_None) {} -}; - // A VM function ------------------------------------------------------------ class PSymbolVMFunction : public PSymbol @@ -469,6 +441,7 @@ public: TArray<Variant> Variants; DWORD Flags; + unsigned AddVariant(PPrototype *proto, TArray<DWORD> &argflags, VMFunction *impl); size_t PropagateMark(); diff --git a/src/thingdef/olddecorations.cpp b/src/thingdef/olddecorations.cpp index 8c1da024c..541f3602c 100644 --- a/src/thingdef/olddecorations.cpp +++ b/src/thingdef/olddecorations.cpp @@ -233,24 +233,24 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) { if (extra.bExplosive) { - type->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_Explode")->Function); + type->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_Explode")->Variants[0].Implementation); } } else { // The first frame plays the death sound and // the second frame makes it nonsolid. - type->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_Scream")->Function); + type->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_Scream")->Variants[0].Implementation); if (extra.bSolidOnDeath) { } else if (extra.DeathStart + 1 < extra.DeathEnd) { - type->OwnedStates[extra.DeathStart+1].SetAction(FindGlobalActionFunction("A_NoBlocking")->Function); + type->OwnedStates[extra.DeathStart+1].SetAction(FindGlobalActionFunction("A_NoBlocking")->Variants[0].Implementation); } else { - type->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_ScreamAndUnblock")->Function); + type->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_ScreamAndUnblock")->Variants[0].Implementation); } if (extra.DeathHeight == 0) @@ -282,17 +282,17 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) // The first frame plays the burn sound and // the second frame makes it nonsolid. - type->OwnedStates[extra.FireDeathStart].SetAction(FindGlobalActionFunction("A_ActiveSound")->Function); + type->OwnedStates[extra.FireDeathStart].SetAction(FindGlobalActionFunction("A_ActiveSound")->Variants[0].Implementation); if (extra.bSolidOnBurn) { } else if (extra.FireDeathStart + 1 < extra.FireDeathEnd) { - type->OwnedStates[extra.FireDeathStart+1].SetAction(FindGlobalActionFunction("A_NoBlocking")->Function); + type->OwnedStates[extra.FireDeathStart+1].SetAction(FindGlobalActionFunction("A_NoBlocking")->Variants[0].Implementation); } else { - type->OwnedStates[extra.FireDeathStart].SetAction(FindGlobalActionFunction("A_ActiveAndUnblock")->Function); + type->OwnedStates[extra.FireDeathStart].SetAction(FindGlobalActionFunction("A_ActiveAndUnblock")->Variants[0].Implementation); } if (extra.BurnHeight == 0) extra.BurnHeight = ((AActor*)(type->Defaults))->height; @@ -313,14 +313,14 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) type->OwnedStates[i].Tics = 5; type->OwnedStates[i].TicRange = 0; type->OwnedStates[i].Misc1 = 0; - type->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeath")->Function); + type->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeath")->Variants[0].Implementation); i = type->NumOwnedStates - 1; type->OwnedStates[i].NextState = &type->OwnedStates[i]; type->OwnedStates[i].Tics = 1; type->OwnedStates[i].TicRange = 0; type->OwnedStates[i].Misc1 = 0; - type->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeathChunks")->Function); + type->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeathChunks")->Variants[0].Implementation); bag.statedef.SetStateLabel("Ice", &type->OwnedStates[extra.IceDeathStart]); } else if (extra.bGenericIceDeath) diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index 1b253ec89..6a1f4fb00 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -188,7 +188,7 @@ AFuncDesc *FindFunction(const char * string); void ParseStates(FScanner &sc, PClassActor *actor, AActor *defaults, Baggage &bag); -PSymbolActionFunction *FindGlobalActionFunction(const char *name); +PFunction *FindGlobalActionFunction(const char *name); //========================================================================== // @@ -201,7 +201,7 @@ void SetReplacement(FScanner &sc, PClassActor *info, FName replaceName); void HandleActorFlag(FScanner &sc, Baggage &bag, const char *part1, const char *part2, int mod); void FinishActor(const FScriptPosition &sc, PClassActor *info, Baggage &bag); -FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, char type, bool constant); +FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool constant); enum diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index c45774d66..bf99ee363 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -553,9 +553,9 @@ FVariableInfo *FindVariable(const char * string, const PClass *cls) // //========================================================================== -PSymbolActionFunction *FindGlobalActionFunction(const char *name) +PFunction *FindGlobalActionFunction(const char *name) { - return dyn_cast<PSymbolActionFunction>(RUNTIME_CLASS(AActor)->Symbols.FindSymbol(name, false)); + return dyn_cast<PFunction>(RUNTIME_CLASS(AActor)->Symbols.FindSymbol(name, false)); } diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 59c1bcf08..17cb90135 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -67,35 +67,46 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def); // //========================================================================== -FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, char type, bool constant) +FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool constant) { FxExpression *x = NULL; int v; - switch(type) + if (type == TypeSound) { - case 'S': - case 's': // Sound name sc.MustGetString(); x = new FxConstant(FSoundID(sc.String), sc); - break; - - case 'M': - case 'm': // Actor name + } + else if (type == TypeSInt32 || type == TypeFloat64) + { + x = ParseExpression (sc, cls); + if (constant && !x->isConstant()) + { + sc.ScriptMessage("Default parameter must be constant."); + FScriptPosition::ErrorCounter++; + } + // Do automatic coercion between ints and floats. + if (type == TypeSInt32) + { + if (x->ValueType != VAL_Int) + { + x = new FxIntCast(x); + } + } + else + { + if (x->ValueType != VAL_Float) + { + x = new FxFloatCast(x); + } + } + } + else if (type == TypeName || type == TypeString) + { sc.SetEscape(true); sc.MustGetString(); sc.SetEscape(false); - x = new FxClassTypeCast(RUNTIME_CLASS(AActor), new FxConstant(FName(sc.String), sc)); - break; - - case 'N': - case 'n': // name - case 'T': - case 't': // String - sc.SetEscape(true); - sc.MustGetString(); - sc.SetEscape(false); - if (type == 'n' || type == 'N') + if (type == TypeName) { x = new FxConstant(sc.String[0] ? FName(sc.String) : NAME_None, sc); } @@ -103,10 +114,9 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, char type, bool con { x = new FxConstant(strbin1(sc.String), sc); } - break; - - case 'C': - case 'c': // Color + } + else if (type == TypeColor) + { sc.MustGetString (); if (sc.Compare("none")) { @@ -122,16 +132,12 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, char type, bool con // 0 needs to be the default so we have to mark the color. v = MAKEARGB(1, RPART(c), GPART(c), BPART(c)); } - { - ExpVal val; - val.Type = VAL_Color; - val.Int = v; - x = new FxConstant(val, sc); - break; - } - - case 'L': - case 'l': + ExpVal val; + val.Type = VAL_Color; + val.Int = v; + x = new FxConstant(val, sc); + } + else if (type == TypeState) { // This forces quotation marks around the state name. sc.MustGetToken(TK_StringConst); @@ -151,39 +157,18 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, char type, bool con { x = new FxMultiNameState(sc.String, sc); } - break; } - - case 'X': - case 'x': - case 'Y': - case 'y': - x = ParseExpression (sc, cls); - if (constant && !x->isConstant()) - { - sc.ScriptMessage("Default parameter must be constant."); - FScriptPosition::ErrorCounter++; - } - // Do automatic coercion between ints and floats. - if (type == 'x' || type == 'X') - { - if (x->ValueType != VAL_Int) - { - x = new FxIntCast(x); - } - } - else - { - if (x->ValueType != VAL_Float) - { - x = new FxFloatCast(x); - } - } - break; - - default: - assert(false); - return NULL; + else if (type->GetClass() == RUNTIME_CLASS(PClassPointer)) + { // Actor name + sc.SetEscape(true); + sc.MustGetString(); + sc.SetEscape(false); + x = new FxClassTypeCast(static_cast<PClassPointer *>(type)->ClassRestriction, new FxConstant(FName(sc.String), sc)); + } + else + { + assert(false && "Unknown parameter type"); + x = NULL; } return x; } @@ -917,15 +902,12 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag) static void ParseActionDef (FScanner &sc, PClassActor *cls) { - enum - { - OPTIONAL = 1 - }; - bool error = false; const AFuncDesc *afd; FName funcname; - FString args; + TArray<PType *> rets; + TArray<PType *> args; + TArray<DWORD> argflags; if (sc.LumpNum == -1 || Wads.GetLumpFile(sc.LumpNum) > 0) { @@ -934,6 +916,11 @@ static void ParseActionDef (FScanner &sc, PClassActor *cls) } sc.MustGetToken(TK_Native); + // check for a return value + if (sc.CheckToken(TK_Int) || sc.CheckToken(TK_Bool)) + { + rets.Push(TypeSInt32); + } sc.MustGetToken(TK_Identifier); funcname = sc.String; afd = FindFunction(sc.String); @@ -942,13 +929,18 @@ static void ParseActionDef (FScanner &sc, PClassActor *cls) sc.ScriptMessage ("The function '%s' has not been exported from the executable.", sc.String); error++; } + args.Push(NewClassPointer(cls)), argflags.Push(0); // implied self pointer + args.Push(NewClassPointer(RUNTIME_CLASS(AActor))), argflags.Push(0); // implied stateowner pointer + args.Push(TypeState), argflags.Push(0); // implied callingstate pointer + sc.MustGetToken('('); if (!sc.CheckToken(')')) { while (sc.TokenType != ')') { int flags = 0; - char type = '@'; + PType *type = NULL; + PClass *restrict = NULL; // Retrieve flags before type name for (;;) @@ -967,32 +959,42 @@ static void ParseActionDef (FScanner &sc, PClassActor *cls) { case TK_Bool: case TK_Int: - type = 'x'; + type = TypeSInt32; break; case TK_Float: - type = 'y'; + type = TypeFloat64; break; - case TK_Sound: type = 's'; break; - case TK_String: type = 't'; break; - case TK_Name: type = 'n'; break; - case TK_State: type = 'l'; break; - case TK_Color: type = 'c'; break; + case TK_Sound: type = TypeSound; break; + case TK_String: type = TypeString; break; + case TK_Name: type = TypeName; break; + case TK_State: type = TypeState; break; + case TK_Color: type = TypeColor; break; case TK_Class: sc.MustGetToken('<'); - sc.MustGetToken(TK_Identifier); // Skip class name, since the parser doesn't care + sc.MustGetToken(TK_Identifier); // Get class name + restrict = PClass::FindClass(sc.String); + if (restrict == NULL) + { + sc.ScriptMessage("Unknown class type %s", sc.String); + FScriptPosition::ErrorCounter++; + } + else + { + type = NewClassPointer(restrict); + } sc.MustGetToken('>'); - type = 'm'; break; case TK_Ellipsis: - type = '+'; + // Making the final type NULL signals a varargs function. + type = NULL; sc.MustGetToken(')'); sc.UnGet(); break; default: sc.ScriptMessage ("Unknown variable type %s", sc.TokenName(sc.TokenType, sc.String).GetChars()); - type = 'x'; + type = TypeSInt32; FScriptPosition::ErrorCounter++; break; } @@ -1008,16 +1010,13 @@ static void ParseActionDef (FScanner &sc, PClassActor *cls) if (sc.CheckToken('=')) { - flags |= OPTIONAL; + flags |= VARF_Optional; FxExpression *def = ParseParameter(sc, cls, type, true); delete def; } - if (!(flags & OPTIONAL) && type != '+') - { - type -= 'a' - 'A'; - } - args += type; + args.Push(type); + argflags.Push(flags); sc.MustGetAnyToken(); if (sc.TokenType != ',' && sc.TokenType != ')') { @@ -1028,14 +1027,14 @@ static void ParseActionDef (FScanner &sc, PClassActor *cls) sc.MustGetToken(';'); if (afd != NULL) { - PSymbolActionFunction *sym = new PSymbolActionFunction(funcname); - sym->Arguments = args; - sym->Function = *(afd->VMPointer); + PFunction *sym = new PFunction(funcname); + sym->AddVariant(NewPrototype(rets, args), argflags, *(afd->VMPointer)); + sym->Flags = VARF_Method | VARF_Action; if (error) { FScriptPosition::ErrorCounter++; } - else if (cls->Symbols.AddSymbol (sym) == NULL) + else if (cls->Symbols.AddSymbol(sym) == NULL) { delete sym; sc.ScriptMessage ("'%s' is already defined in class '%s'.", diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index fb3ecf673..dafe4d76c 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -100,7 +100,7 @@ bool DoActionSpecials(FScanner &sc, FState & state, Baggage &bag, FStateTempCall sc.ScriptError ("Too many arguments to %s", specname.GetChars()); } - tcall->Function = FindGlobalActionFunction("A_CallSpecial")->Function; + tcall->Function = FindGlobalActionFunction("A_CallSpecial")->Variants[0].Implementation; return true; } return false; @@ -312,18 +312,29 @@ do_stop: goto endofstate; } - PSymbolActionFunction *afd = dyn_cast<PSymbolActionFunction>(bag.Info->Symbols.FindSymbol (FName(sc.String, true), true)); + PFunction *afd = dyn_cast<PFunction>(bag.Info->Symbols.FindSymbol(FName(sc.String, true), true)); if (afd != NULL) { - tcall->Function = afd->Function; - if (!afd->Arguments.IsEmpty()) + tcall->Function = afd->Variants[0].Implementation; + const TArray<PType *> ¶ms = afd->Variants[0].Proto->ArgumentTypes; + const TArray<DWORD> ¶mflags = afd->Variants[0].ArgFlags; + int numparams = (int)params.Size(); + int pnum = 0; + if (afd->Flags & VARF_Method) + { + numparams--; + pnum++; + } + if (afd->Flags & VARF_Action) + { + numparams -= 2; + pnum += 2; + } + if (numparams > 0) { - const char *params = afd->Arguments.GetChars(); - int numparams = (int)afd->Arguments.Len(); - int v; - if (!islower(*params)) + if (!(paramflags[pnum] & VARF_Optional)) { sc.MustGetStringName("("); } @@ -335,13 +346,10 @@ do_stop: } } - bool varargs = params[numparams - 1] == '+'; - int varargcount = 0; - - while (*params) + while (numparams > 0) { FxExpression *x; - if ((*params == 'l' || *params == 'L') && sc.CheckNumber()) + if (params[pnum] == TypeState && sc.CheckNumber()) { // Special case: State label as an offset if (sc.Number > 0 && statestring.Len() > 1) @@ -349,7 +357,7 @@ do_stop: sc.ScriptError("You cannot use state jumps commands with a jump offset on multistate definitions\n"); } - v=sc.Number; + v = sc.Number; if (v<0) { sc.ScriptError("Negative jump offsets are not allowed"); @@ -367,22 +375,23 @@ do_stop: else { // Use the generic parameter parser for everything else - x = ParseParameter(sc, bag.Info, *params, false); + x = ParseParameter(sc, bag.Info, params[pnum], false); } tcall->Parameters.Push(new FxParameter(x)); - params++; - varargcount++; - if (*params) + pnum++; + numparams--; + if (numparams > 0) { - if (*params == '+') - { + if (params[pnum] == NULL) + { // varargs function if (sc.CheckString(")")) { goto endofstate; } - params--; + pnum--; + numparams++; } - else if ((islower(*params) || *params=='!') && sc.CheckString(")")) + else if ((paramflags[pnum] & VARF_Optional) && sc.CheckString(")")) { goto endofstate; } From fd9c450c6e5db2d92e93b13b81986d3062b7d96f Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 21 Aug 2013 22:28:53 -0500 Subject: [PATCH 131/232] Fix merge for ACS's DropItem --- src/p_acs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 57a4c51c0..905fa574f 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -5238,7 +5238,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) const char *type = FBehavior::StaticLookupString(args[1]); int amount = argCount >= 3? args[2] : -1; int chance = argCount >= 4? args[3] : 256; - const PClass *cls = PClass::FindClass(type); + PClassActor *cls = PClass::FindActor(type); int cnt = 0; if (cls != NULL) { From 6198c000af510a6c532fed99453c8b3d29bef6bf Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 21 Aug 2013 22:31:40 -0500 Subject: [PATCH 132/232] Fix A_DropItem from merge --- src/thingdef/thingdef_codeptr.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 0114041f2..4cd725805 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -5213,10 +5213,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetDamageType) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DropItem) { - ACTION_PARAM_START(3); - ACTION_PARAM_CLASS(spawntype, 0); - ACTION_PARAM_INT(amount, 1); - ACTION_PARAM_INT(chance, 2); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS (spawntype, AActor); + PARAM_INT_OPT (amount) { amount = -1; } + PARAM_INT_OPT (chance) { chance = 256; } P_DropItem(self, spawntype, amount, chance); + return 0; } From e50c00c8564f7feac91bd902f4b1e4e535a423fd Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 21 Aug 2013 22:36:46 -0500 Subject: [PATCH 133/232] Add generic integer setters and getters for PInt and PFloat types --- src/dobjtype.cpp | 126 +++++++++++++++++++++++++++++++++++++++++++++++ src/dobjtype.h | 12 +++++ 2 files changed, 138 insertions(+) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 68e5e8b31..22dec47a8 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -206,6 +206,29 @@ PType::~PType() { } +//========================================================================== +// +// PType :: SetValue +// +//========================================================================== + +void PType::SetValue(void *addr, int val) +{ + assert(0 && "Cannot set value for this type"); +} + +//========================================================================== +// +// PType :: GetValue +// +//========================================================================== + +int PType::GetValueInt(void *addr) +{ + assert(0 && "Cannot get value for this type"); + return 0; +} + //========================================================================== // // PType :: IsMatch @@ -360,6 +383,69 @@ PInt::PInt(unsigned int size, bool unsign) { } +//========================================================================== +// +// PInt :: SetValue +// +//========================================================================== + +void PInt::SetValue(void *addr, int val) +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + if (Size == 4) + { + *(int *)addr = val; + } + else if (Size == 1) + { + *(BYTE *)addr = val; + } + else if (Size == 2) + { + *(WORD *)addr = val; + } + else if (Size == 8) + { + *(QWORD *)addr = val; + } + else + { + assert(0 && "Unhandled integer size"); + } +} + +//========================================================================== +// +// PInt :: GetValueInt +// +//========================================================================== + +int PInt::GetValueInt(void *addr) +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + if (Size == 4) + { + return *(int *)addr; + } + else if (Size == 1) + { + return Unsigned ? *(BYTE *)addr : *(SBYTE *)addr; + } + else if (Size == 2) + { + return Unsigned ? *(WORD *)addr : *(SWORD *)addr; + } + else if (Size == 8) + { // truncated output + return (int)*(QWORD *)addr; + } + else + { + assert(0 && "Unhandled integer size"); + return 0; + } +} + /* PFloat *****************************************************************/ IMPLEMENT_CLASS(PFloat) @@ -386,6 +472,46 @@ PFloat::PFloat(unsigned int size) { } +//========================================================================== +// +// PFloat :: SetValue +// +//========================================================================== + +void PFloat::SetValue(void *addr, int val) +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + if (Size == 4) + { + *(float *)addr = (float)val; + } + else + { + assert(Size == 8); + *(double *)addr = val; + } +} + +//========================================================================== +// +// PFloat :: GetValueInt +// +//========================================================================== + +int PFloat::GetValueInt(void *addr) +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + if (Size == 4) + { + return xs_ToInt(*(float *)addr); + } + else + { + assert(Size == 8); + return xs_ToInt(*(double *)addr); + } +} + /* PString ****************************************************************/ IMPLEMENT_CLASS(PString) diff --git a/src/dobjtype.h b/src/dobjtype.h index 17748b13b..beab89712 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -167,6 +167,12 @@ public: PType(unsigned int size, unsigned int align); virtual ~PType(); + // Sets the value of a variable of this type at (addr) + virtual void SetValue(void *addr, int val); + + // Gets the value of a variable of this type at (addr) + virtual int GetValueInt(void *addr); + // Returns true if this type matches the two identifiers. Referring to the // above table, any type is identified by at most two characteristics. Each // type that implements this function will cast these to the appropriate type. @@ -219,6 +225,9 @@ class PInt : public PBasicType public: PInt(unsigned int size, bool unsign); + virtual void SetValue(void *addr, int val); + virtual int GetValueInt(void *addr); + bool Unsigned; protected: PInt(); @@ -229,6 +238,9 @@ class PFloat : public PBasicType DECLARE_CLASS(PFloat, PBasicType); public: PFloat(unsigned int size); + + virtual void SetValue(void *addr, int val); + virtual int GetValueInt(void *addr); protected: PFloat(); }; From 4cf0ef7e3f8ac0ae4b9a6b016fdf9215a630e087 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 21 Aug 2013 22:38:05 -0500 Subject: [PATCH 134/232] Minor PField changes. - Rename FieldOffset and FieldType so they no longer have the "Field" prefix - Add a Flags field. --- src/dobjtype.cpp | 6 +++--- src/dobjtype.h | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 22dec47a8..4d6056c3a 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -1099,10 +1099,10 @@ PField *PStruct::AddField(FName name, PType *type) PField *field = new PField(name, type); // The new field is added to the end of this struct, alignment permitting. - field->FieldOffset = (Size + (type->Align - 1)) & ~(type->Align - 1); + field->Offset = (Size + (type->Align - 1)) & ~(type->Align - 1); // Enlarge this struct to enclose the new field. - Size = field->FieldOffset + type->Size; + Size = field->Offset + type->Size; // This struct's alignment is the same as the largest alignment of any of // its fields. @@ -1161,7 +1161,7 @@ IMPLEMENT_CLASS(PField) //========================================================================== PField::PField() -: PSymbol(NAME_None) +: PSymbol(NAME_None), Offset(0), Type(NULL), Flags(0) { } diff --git a/src/dobjtype.h b/src/dobjtype.h index beab89712..aa96942d9 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -325,10 +325,12 @@ class PField : public PSymbol DECLARE_CLASS(PField, PSymbol); HAS_OBJECT_POINTERS public: - PField(FName name, PType *type) : PSymbol(name), FieldOffset(0), FieldType(type) {} + PField(FName name, PType *type) : PSymbol(name), Offset(0), Type(type), Flags(0) {} + PField(FName name, PType *type, DWORD flags) : PSymbol(name), Offset(0), Type(type), Flags(flags) {} - unsigned int FieldOffset; - PType *FieldType; + unsigned int Offset; + PType *Type; + DWORD Flags; protected: PField(); }; From 5aff8156ba08927051eaef5651fe2da5f5aabcc3 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 21 Aug 2013 22:39:28 -0500 Subject: [PATCH 135/232] Use PField and not PSymbolVariable for ACS's Get/SetUserVariable --- src/dobjtype.h | 1 + src/p_acs.cpp | 81 ++++++++++++++++++++++++-------------------------- 2 files changed, 40 insertions(+), 42 deletions(-) diff --git a/src/dobjtype.h b/src/dobjtype.h index aa96942d9..a51eaa16d 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -16,6 +16,7 @@ #define VARF_Optional (1<<0) // func param is optional #define VARF_Method (1<<1) // func has an implied self parameter #define VARF_Action (1<<2) // func has implied owner and state parameters +#define VARF_Native (1<<3) // func is native code/don't auto serialize field // Symbol information ------------------------------------------------------- diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 905fa574f..a2ab1d5bf 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4273,59 +4273,56 @@ int DLevelScript::LineFromID(int id) } } +bool GetVarAddrType(AActor *self, FName varname, int index, void *&addr, PType *&type) +{ + PField *var = dyn_cast<PField>(self->GetClass()->Symbols.FindSymbol(varname, true)); + PArray *arraytype; + BYTE *baddr = reinterpret_cast<BYTE *>(self); + + if (var == NULL || (var->Flags & VARF_Native)) + { + return false; + } + type = var->Type; + arraytype = dyn_cast<PArray>(type); + if (arraytype != NULL) + { + // unwrap contained type + type = arraytype->ElementType; + // offset by index (if in bounds) + if ((unsigned)index < arraytype->ElementCount) + { // out of bounds + return false; + } + baddr += arraytype->ElementSize * index; + } + else if (index != 0) + { // ignore attempts to set indexed values on non-arrays + return false; + } + addr = baddr; + return true; +} + static void SetUserVariable(AActor *self, FName varname, int index, int value) { - int max; - PSymbolVariable *var = dyn_cast<PSymbolVariable>(self->GetClass()->Symbols.FindSymbol(varname, true)); + void *addr; + PType *type; - if (var == NULL || !var->bUserVar) + if (GetVarAddrType(self, varname, index, addr, type)) { - return; - } - if (var->ValueType.Type == VAL_Int) - { - max = 1; - } - else if (var->ValueType.Type == VAL_Array && var->ValueType.BaseType == VAL_Int) - { - max = var->ValueType.size; - } - else - { - return; - } - // Set the value of the specified user variable. - if (index >= 0 && index < max) - { - ((int *)(reinterpret_cast<BYTE *>(self) + var->offset))[index] = value; + type->SetValue(addr, value); } } static int GetUserVariable(AActor *self, FName varname, int index) { - int max; - PSymbolVariable *var = dyn_cast<PSymbolVariable>(self->GetClass()->Symbols.FindSymbol(varname, true)); + void *addr; + PType *type; - if (var == NULL || !var->bUserVar) + if (GetVarAddrType(self, varname, index, addr, type)) { - return 0; - } - if (var->ValueType.Type == VAL_Int) - { - max = 1; - } - else if (var->ValueType.Type == VAL_Array && var->ValueType.BaseType == VAL_Int) - { - max = var->ValueType.size; - } - else - { - return 0; - } - // Get the value of the specified user variable. - if (index >= 0 && index < max) - { - return ((int *)(reinterpret_cast<BYTE *>(self) + var->offset))[index]; + return type->GetValueInt(addr); } return 0; } From 6aee7833d0d3107cf6ce434106e2724dba78624a Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 21 Aug 2013 22:51:12 -0500 Subject: [PATCH 136/232] Use PField instead of PSymbolVariable for SetMapThingUserData() --- src/p_setup.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index de760008f..9f1708aff 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1686,18 +1686,18 @@ static void SetMapThingUserData(AActor *actor, unsigned udi) { FName varname = MapThingsUserData[udi].Property; int value = MapThingsUserData[udi].Value; - PSymbolVariable *var = dyn_cast<PSymbolVariable>(actor->GetClass()->Symbols.FindSymbol(varname, true)); + PField *var = dyn_cast<PField>(actor->GetClass()->Symbols.FindSymbol(varname, true)); udi++; - if (var == NULL || var->bUserVar || var->ValueType.Type != VAL_Int) + if (var == NULL || (var->Flags & VARF_Native) || !var->Type->IsKindOf(RUNTIME_CLASS(PBasicType))) { DPrintf("%s is not a user variable in class %s\n", varname.GetChars(), actor->GetClass()->TypeName.GetChars()); } else { // Set the value of the specified user variable. - *(int *)(reinterpret_cast<BYTE *>(actor) + var->offset) = value; + var->Type->SetValue(reinterpret_cast<BYTE *>(actor) + var->Offset, value); } } } From 01822c002fd01dc77d9aca9f679e8a6e6b2ad71e Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 21 Aug 2013 22:58:12 -0500 Subject: [PATCH 137/232] Use PField instead of PSymbolVariable for A_SetUserVar/Array --- src/thingdef/thingdef_codeptr.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 4cd725805..0b1884405 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -4365,16 +4365,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserVar) PARAM_NAME (varname); PARAM_INT (value); - PSymbolVariable *var = dyn_cast<PSymbolVariable>(self->GetClass()->Symbols.FindSymbol(varname, true)); + PField *var = dyn_cast<PField>(self->GetClass()->Symbols.FindSymbol(varname, true)); - if (var == NULL || !var->bUserVar || var->ValueType.Type != VAL_Int) + if (var == NULL || (var->Flags & VARF_Native) || !var->Type->IsKindOf(RUNTIME_CLASS(PBasicType))) { Printf("%s is not a user variable in class %s\n", varname.GetChars(), self->GetClass()->TypeName.GetChars()); return 0; } // Set the value of the specified user variable. - *(int *)(reinterpret_cast<BYTE *>(self) + var->offset) = value; + var->Type->SetValue(reinterpret_cast<BYTE *>(self) + var->Offset, value); return 0; } @@ -4391,22 +4391,25 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserArray) PARAM_INT (pos); PARAM_INT (value); - PSymbolVariable *var = dyn_cast<PSymbolVariable>(self->GetClass()->Symbols.FindSymbol(varname, true)); + PField *var = dyn_cast<PField>(self->GetClass()->Symbols.FindSymbol(varname, true)); - if (var == NULL || !var->bUserVar || var->ValueType.Type != VAL_Array || var->ValueType.BaseType != VAL_Int) + if (var == NULL || (var->Flags & VARF_Native) || + !var->Type->IsKindOf(RUNTIME_CLASS(PArray)) || + !static_cast<PArray *>(var->Type)->ElementType->IsKindOf(RUNTIME_CLASS(PBasicType))) { Printf("%s is not a user array in class %s\n", varname.GetChars(), self->GetClass()->TypeName.GetChars()); return 0; } - if (pos < 0 || pos >= var->ValueType.size) + PArray *arraytype = static_cast<PArray *>(var->Type); + if ((unsigned)pos >= arraytype->ElementCount) { Printf("%d is out of bounds in array %s in class %s\n", pos, varname.GetChars(), self->GetClass()->TypeName.GetChars()); return 0; } // Set the value of the specified user array at index pos. - ((int *)(reinterpret_cast<BYTE *>(self) + var->offset))[pos] = value; + arraytype->ElementType->SetValue(reinterpret_cast<BYTE *>(self) + var->Offset + arraytype->ElementSize * pos, value); return 0; } From d798c7896ce3fc1929a203979461cfce5791f1bc Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 21 Aug 2013 23:01:41 -0500 Subject: [PATCH 138/232] Remove FxGlobalVariable class --- src/thingdef/thingdef_exp.h | 17 -------- src/thingdef/thingdef_expression.cpp | 64 ---------------------------- 2 files changed, 81 deletions(-) diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index e6a6d4941..30ad5c3f3 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -690,23 +690,6 @@ public: }; -//========================================================================== -// -// FxGlobalVariable -// -//========================================================================== - -class FxGlobalVariable : public FxExpression -{ -public: - PSymbolVariable *var; - bool AddressRequested; - - FxGlobalVariable(PSymbolVariable*, const FScriptPosition&); - FxExpression *Resolve(FCompileContext&); - void RequestAddress(); -}; - //========================================================================== // // FxClassMember diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index f28a3bb8b..e704d5c9e 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -2348,12 +2348,6 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as global constant\n", Identifier.GetChars()); newex = FxConstant::MakeConstant(sym, ScriptPosition); } - else if (sym->IsKindOf(RUNTIME_CLASS(PSymbolVariable))) // global variables will always be native - { - PSymbolVariable *vsym = static_cast<PSymbolVariable*>(sym); - ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as global variable, address %d\n", Identifier.GetChars(), vsym->offset); - newex = new FxGlobalVariable(vsym, ScriptPosition); - } else { ScriptPosition.Message(MSG_ERROR, "Invalid global identifier '%s'\n", Identifier.GetChars()); @@ -2444,64 +2438,6 @@ ExpEmit FxSelf::Emit(VMFunctionBuilder *build) // //========================================================================== -FxGlobalVariable::FxGlobalVariable(PSymbolVariable *mem, const FScriptPosition &pos) -: FxExpression(pos) -{ - var = mem; - AddressRequested = false; -} - -//========================================================================== -// -// -// -//========================================================================== - -void FxGlobalVariable::RequestAddress() -{ - AddressRequested = true; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxGlobalVariable::Resolve(FCompileContext&) -{ - CHECKRESOLVED(); - switch (var->ValueType.Type) - { - case VAL_Int: - case VAL_Bool: - ValueType = VAL_Int; - break; - - case VAL_Float: - case VAL_Fixed: - case VAL_Angle: - ValueType = VAL_Float; - - case VAL_Object: - case VAL_Class: - ValueType = var->ValueType; - break; - - default: - ScriptPosition.Message(MSG_ERROR, "Invalid type for global variable"); - delete this; - return NULL; - } - return this; -} - -//========================================================================== -// -// -// -//========================================================================== - FxClassMember::FxClassMember(FxExpression *x, PSymbolVariable* mem, const FScriptPosition &pos) : FxExpression(pos) { From 3f6c3fa927f6802321d88f2ffb8541e1140c899c Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 21 Aug 2013 23:19:46 -0500 Subject: [PATCH 139/232] Remove unused GetVariableValue() --- src/thingdef/thingdef_expression.cpp | 68 ---------------------------- 1 file changed, 68 deletions(-) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index e704d5c9e..aed00e339 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -130,74 +130,6 @@ static PSymbol *FindDecorateBuiltinFunction(FName funcname, VMNativeFunction::Na // //========================================================================== -static ExpVal GetVariableValue (void *address, FExpressionType &type) -{ - // NOTE: This cannot access native variables of types - // char, short and float. These need to be redefined if necessary! - ExpVal ret; - - switch(type.Type) - { - case VAL_Int: - ret.Type = VAL_Int; - ret.Int = *(int*)address; - break; - - case VAL_Sound: - ret.Type = VAL_Sound; - ret.Int = *(FSoundID*)address; - break; - - case VAL_Name: - ret.Type = VAL_Name; - ret.Int = *(FName*)address; - break; - - case VAL_Color: - ret.Type = VAL_Color; - ret.Int = *(int*)address; - break; - - case VAL_Bool: - ret.Type = VAL_Int; - ret.Int = *(bool*)address; - break; - - case VAL_Float: - ret.Type = VAL_Float; - ret.Float = *(double*)address; - break; - - case VAL_Fixed: - ret.Type = VAL_Float; - ret.Float = (*(fixed_t*)address) / 65536.; - break; - - case VAL_Angle: - ret.Type = VAL_Float; - ret.Float = (*(angle_t*)address) * 90./ANGLE_90; // intentionally not using ANGLE_1 - break; - - case VAL_Object: - case VAL_Class: - ret.Type = ExpValType(type.Type); // object and class pointers don't retain their specific class information as values - ret.pointer = *(void**)address; - break; - - default: - ret.Type = VAL_Unknown; - ret.pointer = NULL; - break; - } - return ret; -} - -//========================================================================== -// -// -// -//========================================================================== - ExpEmit FxExpression::Emit (VMFunctionBuilder *build) { ScriptPosition.Message(MSG_ERROR, "Unemitted expression found"); From a69089ffd712342361950ef1004819dc07ddb963 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 23 Aug 2013 21:43:56 -0500 Subject: [PATCH 140/232] Change disassembly dumps to be controlled from one spot - Instead of changing three places to turn disassembly dumps on and off, do it with just one place. As a side effect, this now handles the case where the dump file can't be opened. --- src/thingdef/thingdef.cpp | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 3868c3fca..049e017bc 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -280,7 +280,11 @@ static void FinishThingdef() unsigned i, j; int codesize = 0; +#if 1 FILE *dump = fopen("disasm.txt", "w"); +#else + FILE *dump = NULL; +#endif for (i = 0; i < StateTempCalls.Size(); ++i) { FStateTempCall *tcall = StateTempCalls[i]; @@ -317,13 +321,15 @@ static void FinishThingdef() VMScriptFunction *sfunc = buildit.MakeFunction(); sfunc->NumArgs = NAP; func = sfunc; -#if 1 - char label[64]; - int labellen = mysnprintf(label, countof(label), "Function %s.States[%d] (*%d)", - tcall->ActorClass->TypeName.GetChars(), tcall->FirstState, tcall->NumStates); - DumpFunction(dump, sfunc, label, labellen); - codesize += sfunc->CodeSize; -#endif + + if (dump != NULL) + { + char label[64]; + int labellen = mysnprintf(label, countof(label), "Function %s.States[%d] (*%d)", + tcall->ActorClass->TypeName.GetChars(), tcall->FirstState, tcall->NumStates); + DumpFunction(dump, sfunc, label, labellen); + codesize += sfunc->CodeSize; + } } for (int k = 0; k < tcall->NumStates; ++k) { @@ -370,8 +376,8 @@ static void FinishThingdef() dmg->SetFunction(sfunc); } def->Damage = sfunc; -#if 1 - if (sfunc != NULL) + + if (dump != NULL && sfunc != NULL) { char label[64]; int labellen = mysnprintf(label, countof(label), "Function %s.Damage", @@ -379,13 +385,13 @@ static void FinishThingdef() DumpFunction(dump, sfunc, label, labellen); codesize += sfunc->CodeSize; } -#endif } } -#if 1 - fprintf(dump, "\n*************************************************************************\n%i code bytes\n", codesize * 4); -#endif - fclose(dump); + if (dump != NULL) + { + fprintf(dump, "\n*************************************************************************\n%i code bytes\n", codesize * 4); + fclose(dump); + } if (errorcount > 0) { I_Error("%d errors during actor postprocessing", errorcount); From 3ea0d1b444c9180b4dbb5d12990aac45973d2fe3 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 23 Aug 2013 21:46:40 -0500 Subject: [PATCH 141/232] Add VM opcodes NOP, LANG, and SANG - To simplify code generation genericizing, add three new opcodes * NOP: No-Operation * LANG: Load Angle - load a BAM angle into a float reg as degrees * SANG: Save Angle - store a float reg into a BEM angle, converting from degrees --- src/zscript/vmdisasm.cpp | 2 ++ src/zscript/vmexec.h | 24 ++++++++++++++++++++++++ src/zscript/vmops.h | 6 ++++++ 3 files changed, 32 insertions(+) diff --git a/src/zscript/vmdisasm.cpp b/src/zscript/vmdisasm.cpp index 35ca6aa1f..e003d1595 100644 --- a/src/zscript/vmdisasm.cpp +++ b/src/zscript/vmdisasm.cpp @@ -1,6 +1,8 @@ #include "vm.h" #include "c_console.h" +#define NOP MODE_AUNUSED | MODE_BUNUSED | MODE_CUNUSED + #define LI MODE_AI | MODE_BCJOINT | MODE_BCIMMS #define LKI MODE_AI | MODE_BCJOINT | MODE_BCKI #define LKF MODE_AF | MODE_BCJOINT | MODE_BCKF diff --git a/src/zscript/vmexec.h b/src/zscript/vmexec.h index be32dd3c1..01c0e28de 100644 --- a/src/zscript/vmexec.h +++ b/src/zscript/vmexec.h @@ -220,6 +220,16 @@ begin: GETADDR(PB,RC,X_READ_NIL); reg.f[a] = *(VM_SWORD *)ptr / 65536.0; NEXTOP; + OP(LANG): + ASSERTF(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.f[a] = (*(VM_UWORD *)ptr >> 1) * (180.0 / 0x40000000); // BAM -> deg + NEXTOP; + OP(LANG_R): + ASSERTF(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.f[a] = (*(VM_UWORD *)ptr >> 1) * (180.0 / 0x40000000); + NEXTOP; OP(LBIT): ASSERTD(a); ASSERTA(B); GETADDR(PB,0,X_READ_NIL); @@ -326,6 +336,17 @@ begin: GETADDR(PA,RC,X_WRITE_NIL); *(VM_SWORD *)ptr = (VM_SWORD)(reg.f[B] * 65536.0); NEXTOP; + OP(SANG): + ASSERTA(a); ASSERTF(B); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + *(VM_UWORD *)ptr = (VM_UWORD)(reg.f[B] * ((1<<30) / 180.0)) << 1; // deg -> BAM + NEXTOP; + OP(SANG_R): + ASSERTA(a); ASSERTF(B); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + *(VM_UWORD *)ptr = (VM_UWORD)(reg.f[B] * ((1<<30) / 180.0)) << 1; + NEXTOP; + OP(SBIT): ASSERTA(a); ASSERTD(B); GETADDR(PA,0,X_WRITE_NIL); @@ -1301,6 +1322,9 @@ begin: ASSERTA(B); ASSERTKA(C); CMPJMP(reg.a[B] == konsta[C].v); NEXTOP; + + OP(NOP): + NEXTOP; } } catch(VMException *exception) diff --git a/src/zscript/vmops.h b/src/zscript/vmops.h index 353dc3e85..125e5463d 100644 --- a/src/zscript/vmops.h +++ b/src/zscript/vmops.h @@ -2,6 +2,8 @@ #define xx(op, name, mode) OP_##op #endif +xx(NOP, nop, NOP), // no operation + // Load constants. xx(LI, li, LI), // load immediate signed 16-bit constant xx(LK, lk, LKI), // load integer constant @@ -35,6 +37,8 @@ xx(LV, lv, RVRPKI), // load vector xx(LV_R, lv, RVRPRI), xx(LX, lx, RFRPKI), // load fixed point xx(LX_R, lx, RFRPRI), +xx(LANG, lang, RFRPKI), // load angle +xx(LANG_R, lang, RFRPRI), xx(LBIT, lbit, RIRPI8), // rA = !!(*rB & C) -- *rB is a byte @@ -57,6 +61,8 @@ xx(SV, sv, RPRVKI), // store vector xx(SV_R, sv, RPRVRI), xx(SX, sx, RPRFKI), // store fixed point xx(SX_R, sx, RPRFRI), +xx(SANG, sang, RPRFKI), // store angle +xx(SANG_R, sang, RPRFRI), xx(SBIT, sbit, RPRII8), // *rA |= C if rB is true, *rA &= ~C otherwise From 2ec3cbddb93ad376a20e753787e3500b10d3ab41 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 23 Aug 2013 21:50:33 -0500 Subject: [PATCH 142/232] Mark PType's GetValueInt method as const --- src/dobjtype.cpp | 6 +++--- src/dobjtype.h | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 4d6056c3a..6d459dc27 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -223,7 +223,7 @@ void PType::SetValue(void *addr, int val) // //========================================================================== -int PType::GetValueInt(void *addr) +int PType::GetValueInt(void *addr) const { assert(0 && "Cannot get value for this type"); return 0; @@ -420,7 +420,7 @@ void PInt::SetValue(void *addr, int val) // //========================================================================== -int PInt::GetValueInt(void *addr) +int PInt::GetValueInt(void *addr) const { assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); if (Size == 4) @@ -498,7 +498,7 @@ void PFloat::SetValue(void *addr, int val) // //========================================================================== -int PFloat::GetValueInt(void *addr) +int PFloat::GetValueInt(void *addr) const { assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); if (Size == 4) diff --git a/src/dobjtype.h b/src/dobjtype.h index a51eaa16d..053b93072 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -172,7 +172,8 @@ public: virtual void SetValue(void *addr, int val); // Gets the value of a variable of this type at (addr) - virtual int GetValueInt(void *addr); + virtual int GetValueInt(void *addr) const; + // Returns true if this type matches the two identifiers. Referring to the // above table, any type is identified by at most two characteristics. Each @@ -227,7 +228,7 @@ public: PInt(unsigned int size, bool unsign); virtual void SetValue(void *addr, int val); - virtual int GetValueInt(void *addr); + virtual int GetValueInt(void *addr) const; bool Unsigned; protected: @@ -241,7 +242,7 @@ public: PFloat(unsigned int size); virtual void SetValue(void *addr, int val); - virtual int GetValueInt(void *addr); + virtual int GetValueInt(void *addr) const; protected: PFloat(); }; From b5d37348f60bb3ef8c964d97a990c8e484b7e701 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 23 Aug 2013 21:52:04 -0500 Subject: [PATCH 143/232] Add code generation simplification methods to PType - To assist with using PType with DECORATE expression code generation, added GetStoreOp(), GetLoadOp(), and GetRegType() to PType. --- src/dobjtype.cpp | 196 +++++++++++++++++++++++++++++++++++++++++++++++ src/dobjtype.h | 20 +++++ 2 files changed, 216 insertions(+) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 6d459dc27..267efe43b 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -229,6 +229,42 @@ int PType::GetValueInt(void *addr) const return 0; } +//========================================================================== +// +// PType :: GetStoreOp +// +//========================================================================== + +int PType::GetStoreOp() const +{ + assert(0 && "Cannot store this type"); + return OP_NOP; +} + +//========================================================================== +// +// PType :: GetLoadOp +// +//========================================================================== + +int PType::GetLoadOp() const +{ + assert(0 && "Cannot load this type"); + return OP_NOP; +} + +//========================================================================== +// +// PType :: GetRegType +// +//========================================================================== + +int PType::GetRegType() const +{ + assert(0 && "No register for this type"); + return REGT_NIL; +} + //========================================================================== // // PType :: IsMatch @@ -446,6 +482,71 @@ int PInt::GetValueInt(void *addr) const } } +//========================================================================== +// +// PInt :: GetStoreOp +// +//========================================================================== + +int PInt::GetStoreOp() const +{ + if (Size == 4) + { + return OP_SW; + } + else if (Size == 1) + { + return OP_SB; + } + else if (Size == 2) + { + return OP_SH; + } + else + { + assert(0 && "Unhandled integer size"); + return OP_NOP; + } +} + +//========================================================================== +// +// PInt :: GetLoadOp +// +//========================================================================== + +int PInt::GetLoadOp() const +{ + if (Size == 4) + { + return OP_LW; + } + else if (Size == 1) + { + return Unsigned ? OP_LBU : OP_LB; + } + else if (Size == 2) + { + return Unsigned ? OP_LHU : OP_LH; + } + else + { + assert(0 && "Unhandled integer size"); + return OP_NOP; + } +} + +//========================================================================== +// +// PInt :: GetRegType +// +//========================================================================== + +int PInt::GetRegType() const +{ + return REGT_INT; +} + /* PFloat *****************************************************************/ IMPLEMENT_CLASS(PFloat) @@ -512,6 +613,57 @@ int PFloat::GetValueInt(void *addr) const } } +//========================================================================== +// +// PFloat :: GetStoreOp +// +//========================================================================== + +int PFloat::GetStoreOp() const +{ + if (Size == 4) + { + return OP_SSP; + } + else + { + assert(Size == 8); + return OP_SDP; + } +} + +//========================================================================== +// +// PFloat :: GetLoadOp +// +//========================================================================== + +int PFloat::GetLoadOp() const +{ + if (Size == 4) + { + return OP_LSP; + } + else + { + assert(Size == 8); + return OP_LDP; + } + assert(0 && "Cannot load this type"); + return OP_NOP; +} + +//========================================================================== +// +// PFloat :: GetRegType +// +//========================================================================== + +int PFloat::GetRegType() const +{ + return REGT_FLOAT; +} + /* PString ****************************************************************/ IMPLEMENT_CLASS(PString) @@ -527,6 +679,17 @@ PString::PString() { } +//========================================================================== +// +// PString :: GetRegType +// +//========================================================================== + +int PString::GetRegType() const +{ + return REGT_STRING; +} + /* PName ******************************************************************/ IMPLEMENT_CLASS(PName) @@ -622,6 +785,39 @@ PPointer::PPointer(PType *pointsat) Align = __alignof(void *); } +//========================================================================== +// +// PPointer :: GetStoreOp +// +//========================================================================== + +int PPointer::GetStoreOp() const +{ + return OP_SP; +} + +//========================================================================== +// +// PPointer :: GetLoadOp +// +//========================================================================== + +int PPointer::GetLoadOp() const +{ + return PointedType->IsKindOf(RUNTIME_CLASS(PClass)) ? OP_LO : OP_LP; +} + +//========================================================================== +// +// PPointer :: GetRegType +// +//========================================================================== + +int PPointer::GetRegType() const +{ + return REGT_POINTER; +} + //========================================================================== // // PPointer :: IsMatch diff --git a/src/dobjtype.h b/src/dobjtype.h index 053b93072..09c6a3fd0 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -174,6 +174,14 @@ public: // Gets the value of a variable of this type at (addr) virtual int GetValueInt(void *addr) const; + // Gets the opcode to store from a register to memory + virtual int GetStoreOp() const; + + // Gets the opcode to load from memory to a register + virtual int GetLoadOp() const; + + // Gets the register type for this type + virtual int GetRegType() const; // Returns true if this type matches the two identifiers. Referring to the // above table, any type is identified by at most two characteristics. Each @@ -229,6 +237,9 @@ public: virtual void SetValue(void *addr, int val); virtual int GetValueInt(void *addr) const; + virtual int GetStoreOp() const; + virtual int GetLoadOp() const; + virtual int GetRegType() const; bool Unsigned; protected: @@ -243,6 +254,9 @@ public: virtual void SetValue(void *addr, int val); virtual int GetValueInt(void *addr) const; + virtual int GetStoreOp() const; + virtual int GetLoadOp() const; + virtual int GetRegType() const; protected: PFloat(); }; @@ -252,6 +266,8 @@ class PString : public PBasicType DECLARE_CLASS(PString, PBasicType); public: PString(); + + virtual int GetRegType() const; }; // Variations of integer types ---------------------------------------------- @@ -295,6 +311,10 @@ public: PType *PointedType; + virtual int GetStoreOp() const; + virtual int GetLoadOp() const; + virtual int GetRegType() const; + virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; protected: From 263b160905870f6aa1c5e96089d17603c5c5230a Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 23 Aug 2013 21:53:54 -0500 Subject: [PATCH 144/232] Add PFixed and PArray types - These are types that are stored as integers but otherwise handled as floating point values. --- src/dobjtype.cpp | 129 ++++++++++++++++++++++++++++++++++++++++++++++- src/dobjtype.h | 29 +++++++++++ 2 files changed, 157 insertions(+), 1 deletion(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 267efe43b..dc1d7aed2 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -70,6 +70,8 @@ PName *TypeName; PSound *TypeSound; PColor *TypeColor; PStatePointer *TypeState; +PFixed *TypeFixed; +PAngle *TypeAngle; // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -314,6 +316,8 @@ void PType::StaticInit() RUNTIME_CLASS(PStruct)->TypeTableType = RUNTIME_CLASS(PStruct); RUNTIME_CLASS(PPrototype)->TypeTableType = RUNTIME_CLASS(PPrototype); RUNTIME_CLASS(PClass)->TypeTableType = RUNTIME_CLASS(PClass); + RUNTIME_CLASS(PFixed)->TypeTableType = RUNTIME_CLASS(PFixed); + RUNTIME_CLASS(PAngle)->TypeTableType = RUNTIME_CLASS(PAngle); TypeTable.AddType(TypeSInt8 = new PInt(1, false)); TypeTable.AddType(TypeUInt8 = new PInt(1, true)); @@ -328,7 +332,8 @@ void PType::StaticInit() TypeTable.AddType(TypeSound = new PSound); TypeTable.AddType(TypeColor = new PColor); TypeTable.AddType(TypeState = new PStatePointer); - + TypeTable.AddType(TypeFixed = new PFixed); + TypeTable.AddType(TypeAngle = new PAngle); } @@ -738,6 +743,128 @@ PColor::PColor() assert(sizeof(PalEntry) == __alignof(PalEntry)); } +/* PFixed *****************************************************************/ + +IMPLEMENT_CLASS(PFixed) + +//========================================================================== +// +// PFixed Default Constructor +// +//========================================================================== + +PFixed::PFixed() +: PFloat(sizeof(fixed_t)) +{ +} + +//========================================================================== +// +// PFixed :: SetValue +// +//========================================================================== + +void PFixed::SetValue(void *addr, int val) +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + *(fixed_t *)addr = val << FRACBITS; +} + +//========================================================================== +// +// PFixed :: GetValueInt +// +//========================================================================== + +int PFixed::GetValueInt(void *addr) const +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + return *(fixed_t *)addr >> FRACBITS; +} + +//========================================================================== +// +// PFixed :: GetStoreOp +// +//========================================================================== + +int PFixed::GetStoreOp() const +{ + return OP_SX; +} + +//========================================================================== +// +// PFixed :: GetLoadOp +// +//========================================================================== + +int PFixed::GetLoadOp() const +{ + return OP_LX; +} + +/* PAngle *****************************************************************/ + +IMPLEMENT_CLASS(PAngle) + +//========================================================================== +// +// PAngle Default Constructor +// +//========================================================================== + +PAngle::PAngle() +: PFloat(sizeof(angle_t)) +{ +} + +//========================================================================== +// +// PAngle :: SetValue +// +//========================================================================== + +void PAngle::SetValue(void *addr, int val) +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + *(angle_t *)addr = Scale(val, ANGLE_90, 90); +} + +//========================================================================== +// +// PAngle :: GetValueInt +// +//========================================================================== + +int PAngle::GetValueInt(void *addr) const +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + return *(angle_t *)addr / ANGLE_1; +} + +//========================================================================== +// +// PAngle :: GetStoreOp +// +//========================================================================== + +int PAngle::GetStoreOp() const +{ + return OP_SANG; +} + +//========================================================================== +// +// PAngle :: GetLoadOp +// +//========================================================================== + +int PAngle::GetLoadOp() const +{ + return OP_LANG; +} + /* PStatePointer **********************************************************/ IMPLEMENT_CLASS(PStatePointer) diff --git a/src/dobjtype.h b/src/dobjtype.h index 09c6a3fd0..c4fdf48b0 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -293,6 +293,33 @@ public: PColor(); }; +// Variations of floating point types --------------------------------------- +// These get converted to floats when they're loaded from memory. + +class PFixed : public PFloat +{ + DECLARE_CLASS(PFixed, PFloat); +public: + PFixed(); + + virtual void SetValue(void *addr, int val); + virtual int GetValueInt(void *addr) const; + virtual int GetStoreOp() const; + virtual int GetLoadOp() const; +}; + +class PAngle : public PFloat +{ + DECLARE_CLASS(PAngle, PFloat); +public: + PAngle(); + + virtual void SetValue(void *addr, int val); + virtual int GetValueInt(void *addr) const; + virtual int GetStoreOp() const; + virtual int GetLoadOp() const; +}; + // Pointers ----------------------------------------------------------------- class PStatePointer : public PInt @@ -639,5 +666,7 @@ extern PName *TypeName; extern PSound *TypeSound; extern PColor *TypeColor; extern PStatePointer *TypeState; +extern PFixed *TypeFixed; +extern PAngle *TypeAngle; #endif From 27ddaad7ca32960179345119c0ce00ed26ff0b8c Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 23 Aug 2013 21:54:35 -0500 Subject: [PATCH 145/232] Set PStatePointer's TypeTableType in PType::StaticInit() - It was forgotten about earlier. --- src/dobjtype.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index dc1d7aed2..7877a79db 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -316,6 +316,7 @@ void PType::StaticInit() RUNTIME_CLASS(PStruct)->TypeTableType = RUNTIME_CLASS(PStruct); RUNTIME_CLASS(PPrototype)->TypeTableType = RUNTIME_CLASS(PPrototype); RUNTIME_CLASS(PClass)->TypeTableType = RUNTIME_CLASS(PClass); + RUNTIME_CLASS(PStatePointer)->TypeTableType = RUNTIME_CLASS(PStatePointer); RUNTIME_CLASS(PFixed)->TypeTableType = RUNTIME_CLASS(PFixed); RUNTIME_CLASS(PAngle)->TypeTableType = RUNTIME_CLASS(PAngle); From 0d1973a659324f238bfcf7fa2770112039c41f07 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 23 Aug 2013 21:56:18 -0500 Subject: [PATCH 146/232] Make PStruct::AddField() check for duplicates - PStruct::AddField() now checks the symbol table for a symbol of the same name before adding a new field. If the name is in use, it returns NULL. --- src/dobjtype.cpp | 11 ++++++++--- src/dobjtype.h | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 7877a79db..fdb85a892 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -1414,11 +1414,12 @@ PStruct::PStruct(FName name, DObject *outer) // // PStruct :: AddField // -// Appends a new field to the end of a struct. +// Appends a new field to the end of a struct. Returns either the new field +// or NULL if a symbol by that name already exists. // //========================================================================== -PField *PStruct::AddField(FName name, PType *type) +PField *PStruct::AddField(FName name, PType *type, DWORD flags) { PField *field = new PField(name, type); @@ -1432,8 +1433,12 @@ PField *PStruct::AddField(FName name, PType *type) // its fields. Align = MAX(Align, type->Align); + if (Symbols.AddSymbol(field) == NULL) + { // name is already in use + delete field; + return NULL; + } Fields.Push(field); - Symbols.AddSymbol(field); return field; } diff --git a/src/dobjtype.h b/src/dobjtype.h index c4fdf48b0..0018d38c4 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -467,7 +467,7 @@ public: TArray<PField *> Fields; PSymbolTable Symbols; - PField *AddField(FName name, PType *type); + PField *AddField(FName name, PType *type, DWORD flags=0); size_t PropagateMark(); protected: From 2f7183b937f1ef76f817f8d498faad4be2cc40b7 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 23 Aug 2013 22:02:51 -0500 Subject: [PATCH 147/232] Use PField instead of PSymbolVariable for DECORATE expressions - The type systems used by PField and FxExpression are completely incompatible, but I think I got the differences taken care of as far as ParseNativeVariable(), ParseUserVariable(), and FxClassMember are concerned. - Support for declaring native bool variables has been removed for the time being. It wasn't used anyway. - Removed PSymbolVariable. --- src/dobject.cpp | 38 +++++++--- src/dobjtype.cpp | 1 - src/dobjtype.h | 15 ---- src/thingdef/thingdef_exp.h | 4 +- src/thingdef/thingdef_expression.cpp | 102 ++++++++------------------- src/thingdef/thingdef_parse.cpp | 44 ++++++------ 6 files changed, 83 insertions(+), 121 deletions(-) diff --git a/src/dobject.cpp b/src/dobject.cpp index 8e209e640..4ca08a79d 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -425,11 +425,22 @@ void DObject::SerializeUserVars(FArchive &arc) while (it.NextPair(pair)) { - PSymbolVariable *var = dyn_cast<PSymbolVariable>(pair->Value); - if (var != NULL && var->bUserVar) + PField *var = dyn_cast<PField>(pair->Value); + if (var != NULL && !(var->Flags & VARF_Native)) { - count = var->ValueType.Type == VAL_Array ? var->ValueType.size : 1; - varloc = (int *)(reinterpret_cast<BYTE *>(this) + var->offset); + PType *type = var->Type; + PArray *arraytype = dyn_cast<PArray>(type); + if (arraytype == NULL) + { + count = 1; + } + else + { + count = arraytype->ElementCount; + type = arraytype->ElementType; + } + assert(type == TypeSInt32); + varloc = (int *)(reinterpret_cast<BYTE *>(this) + var->Offset); arc << var->SymbolName; arc.WriteCount(count); @@ -450,13 +461,24 @@ void DObject::SerializeUserVars(FArchive &arc) arc << varname; while (varname != NAME_None) { - PSymbolVariable *var = dyn_cast<PSymbolVariable>(symt->FindSymbol(varname, true)); + PField *var = dyn_cast<PField>(symt->FindSymbol(varname, true)); DWORD wanted = 0; - if (var != NULL && var->bUserVar) + if (var != NULL && !(var->Flags & VARF_Native)) { - wanted = var->ValueType.Type == VAL_Array ? var->ValueType.size : 1; - varloc = (int *)(reinterpret_cast<BYTE *>(this) + var->offset); + PType *type = var->Type; + PArray *arraytype = dyn_cast<PArray>(type); + if (arraytype != NULL) + { + wanted = arraytype->ElementCount; + type = arraytype->ElementType; + } + else + { + wanted = 1; + } + assert(type == TypeSInt32); + varloc = (int *)(reinterpret_cast<BYTE *>(this) + var->Offset); } count = arc.ReadCount(); for (j = 0; j < MIN(wanted, count); ++j) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index fdb85a892..f10a07ad1 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2287,7 +2287,6 @@ CCMD(typetable) IMPLEMENT_ABSTRACT_CLASS(PSymbol); IMPLEMENT_CLASS(PSymbolConst); -IMPLEMENT_CLASS(PSymbolVariable); IMPLEMENT_POINTY_CLASS(PSymbolVMFunction) DECLARE_POINTER(Function) END_POINTERS diff --git a/src/dobjtype.h b/src/dobjtype.h index 0018d38c4..dad47d44c 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -49,21 +49,6 @@ public: PSymbolConst() : PSymbol(NAME_None) {} }; -// A variable --------------------------------------------------------- - -class PSymbolVariable : public PSymbol -{ - DECLARE_CLASS(PSymbolVariable, PSymbol); -public: - FExpressionType ValueType; - //int size; - intptr_t offset; - bool bUserVar; - - PSymbolVariable(FName name) : PSymbol(name) {} - PSymbolVariable() : PSymbol(NAME_None) {} -}; - // An action function ------------------------------------------------------- struct FState; diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 30ad5c3f3..0c7cfcfa7 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -700,10 +700,10 @@ class FxClassMember : public FxExpression { public: FxExpression *classx; - PSymbolVariable *membervar; + PField *membervar; bool AddressRequested; - FxClassMember(FxExpression*, PSymbolVariable*, const FScriptPosition&); + FxClassMember(FxExpression*, PField*, const FScriptPosition&); ~FxClassMember(); FxExpression *Resolve(FCompileContext&); void RequestAddress(); diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index aed00e339..d5fd9b0d2 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -2261,10 +2261,10 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as class constant\n", Identifier.GetChars()); newex = FxConstant::MakeConstant(sym, ScriptPosition); } - else if (sym->IsKindOf(RUNTIME_CLASS(PSymbolVariable))) + else if (sym->IsKindOf(RUNTIME_CLASS(PField))) { - PSymbolVariable *vsym = static_cast<PSymbolVariable*>(sym); - ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as member variable, index %d\n", Identifier.GetChars(), vsym->offset); + PField *vsym = static_cast<PField*>(sym); + ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as member variable, index %d\n", Identifier.GetChars(), vsym->Offset); newex = new FxClassMember((new FxSelf(ScriptPosition))->Resolve(ctx), vsym, ScriptPosition); } else @@ -2370,7 +2370,7 @@ ExpEmit FxSelf::Emit(VMFunctionBuilder *build) // //========================================================================== -FxClassMember::FxClassMember(FxExpression *x, PSymbolVariable* mem, const FScriptPosition &pos) +FxClassMember::FxClassMember(FxExpression *x, PField* mem, const FScriptPosition &pos) : FxExpression(pos) { classx = x; @@ -2418,30 +2418,35 @@ FxExpression *FxClassMember::Resolve(FCompileContext &ctx) delete this; return NULL; } - switch (membervar->ValueType.Type) + PType *type = membervar->Type; + PArray *arraytype = dyn_cast<PArray>(type); + + if (arraytype != NULL) + { + type = arraytype->ElementType; + } + if (type->IsKindOf(RUNTIME_CLASS(PPointer))) + { + ValueType = VAL_Object; + } + else if (type->IsKindOf(RUNTIME_CLASS(PInt))) { - case VAL_Int: - case VAL_Bool: ValueType = VAL_Int; - break; - - case VAL_Float: - case VAL_Fixed: - case VAL_Angle: + } + else if (type->IsKindOf(RUNTIME_CLASS(PFloat))) + { ValueType = VAL_Float; - break; - - case VAL_Object: - case VAL_Class: - case VAL_Array: - ValueType = membervar->ValueType; - break; - - default: + } + else + { ScriptPosition.Message(MSG_ERROR, "Invalid type for member variable %s", membervar->SymbolName.GetChars()); delete this; return NULL; } + if (arraytype != NULL) + { + ValueType.MakeArray(arraytype->ElementCount); + } return this; } @@ -2452,17 +2457,17 @@ ExpEmit FxClassMember::Emit(VMFunctionBuilder *build) if (AddressRequested) { - if (membervar->offset == 0) + if (membervar->Offset == 0) { return obj; } obj.Free(build); ExpEmit out(build, REGT_POINTER); - build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, build->GetConstantInt((int)membervar->offset)); + build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, build->GetConstantInt((int)membervar->Offset)); return out; } - int offsetreg = build->GetConstantInt((int)membervar->offset); + int offsetreg = build->GetConstantInt((int)membervar->Offset); ExpEmit loc, tmp; if (obj.Konst) @@ -2476,53 +2481,8 @@ ExpEmit FxClassMember::Emit(VMFunctionBuilder *build) obj = newobj; } - switch (membervar->ValueType.Type) - { - case VAL_Int: - case VAL_Sound: - case VAL_Name: - case VAL_Color: - loc = ExpEmit(build, REGT_INT); - build->Emit(OP_LW, loc.RegNum, obj.RegNum, offsetreg); - break; - - case VAL_Bool: - loc = ExpEmit(build, REGT_INT); - // Some implementations have 1 byte bools, and others have - // 4 byte bools. For all I know, there might be some with - // 2 byte bools, too. - build->Emit((sizeof(bool) == 1 ? OP_LBU : sizeof(bool) == 2 ? OP_LHU : OP_LW), - loc.RegNum, obj.RegNum, offsetreg); - break; - - case VAL_Float: - loc = ExpEmit(build, REGT_FLOAT); - build->Emit(OP_LDP, loc.RegNum, obj.RegNum, offsetreg); - break; - - case VAL_Fixed: - loc = ExpEmit(build, REGT_FLOAT); - build->Emit(OP_LX, loc.RegNum, obj.RegNum, offsetreg); - break; - - case VAL_Angle: - loc = ExpEmit(build, REGT_FLOAT); - tmp = ExpEmit(build, REGT_INT); - build->Emit(OP_LW, tmp.RegNum, obj.RegNum, offsetreg); - build->Emit(OP_CAST, loc.RegNum, tmp.RegNum, CAST_I2F); - build->Emit(OP_MULF_RK, loc.RegNum, loc.RegNum, build->GetConstantFloat(90.0 / ANGLE_90)); - tmp.Free(build); - break; - - case VAL_Object: - case VAL_Class: - loc = ExpEmit(build, REGT_POINTER); - build->Emit(OP_LO, loc.RegNum, obj.RegNum, offsetreg); - break; - - default: - assert(0); - } + loc = ExpEmit(build, membervar->Type->GetRegType()); + build->Emit(membervar->Type->GetLoadOp(), loc.RegNum, obj.RegNum, offsetreg); obj.Free(build); return loc; } diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 17cb90135..50a9f7f53 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -288,7 +288,7 @@ static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClassActor *cls) static void ParseNativeVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cls) { - FExpressionType valuetype; + PType *valuetype; if (sc.LumpNum == -1 || Wads.GetLumpFile(sc.LumpNum) > 0) { @@ -301,27 +301,23 @@ static void ParseNativeVariable (FScanner &sc, PSymbolTable *symt, PClassActor * switch (sc.TokenType) { case TK_Int: - valuetype = VAL_Int; + valuetype = TypeSInt32; break; case TK_Float: - valuetype = VAL_Float; + valuetype = TypeFloat64; break; case TK_Angle_t: - valuetype = VAL_Angle; + valuetype = TypeAngle; break; case TK_Fixed_t: - valuetype = VAL_Fixed; - break; - - case TK_Bool: - valuetype = VAL_Bool; + valuetype = TypeFixed; break; case TK_Identifier: - valuetype = VAL_Object; + valuetype = NULL; // Todo: Object type sc.ScriptError("Object type variables not implemented yet!"); break; @@ -343,7 +339,7 @@ static void ParseNativeVariable (FScanner &sc, PSymbolTable *symt, PClassActor * int maxelems = static_cast<FxConstant *>(expr)->GetValue().GetInt(); delete expr; sc.MustGetToken(']'); - valuetype.MakeArray(maxelems); + valuetype = NewArray(valuetype, maxelems); } sc.MustGetToken(';'); @@ -353,18 +349,20 @@ static void ParseNativeVariable (FScanner &sc, PSymbolTable *symt, PClassActor * sc.ScriptError("Unknown native variable '%s'", symname.GetChars()); } - PSymbolVariable *sym = new PSymbolVariable(symname); - sym->offset = vi->address; // todo - sym->ValueType = valuetype; - sym->bUserVar = false; + PField *sym = new PField(symname, valuetype, VARF_Native); + sym->Offset = (unsigned)vi->address; // todo - if (symt->AddSymbol (sym) == NULL) + if (symt->AddSymbol(sym) == NULL) { delete sym; sc.ScriptMessage ("'%s' is already defined in '%s'.", symname.GetChars(), cls? cls->TypeName.GetChars() : "Global"); FScriptPosition::ErrorCounter++; } + else + { + cls->Fields.Push(sym); + } } //========================================================================== @@ -377,7 +375,8 @@ static void ParseNativeVariable (FScanner &sc, PSymbolTable *symt, PClassActor * static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cls) { - FExpressionType valuetype; + PType *type; + int maxelems = 1; // Only non-native classes may have user variables. if (!cls->bRuntimeClass) @@ -392,7 +391,7 @@ static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cl sc.ScriptMessage("User variables must be of type int"); FScriptPosition::ErrorCounter++; } - valuetype = VAL_Int; + type = TypeSInt32; sc.MustGetToken(TK_Identifier); // For now, restrict user variables to those that begin with "user_" to guarantee @@ -407,7 +406,6 @@ static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cl if (sc.CheckToken('[')) { FxExpression *expr = ParseExpression(sc, cls); - int maxelems; if (!expr->isConstant()) { sc.ScriptMessage("Array size must be a constant"); @@ -425,14 +423,12 @@ static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cl FScriptPosition::ErrorCounter++; maxelems = 1; } - valuetype.MakeArray(maxelems); + type = NewArray(type, maxelems); } sc.MustGetToken(';'); - PSymbolVariable *sym = new PSymbolVariable(symname); - sym->offset = cls->Extend(sizeof(int) * (valuetype.Type == VAL_Array ? valuetype.size : 1)); - sym->ValueType = valuetype; - sym->bUserVar = true; + PField *sym = new PField(symname, type, 0); + sym->Offset = cls->Extend(sizeof(int) * maxelems); if (symt->AddSymbol(sym) == NULL) { delete sym; From 956d754804cf2c51926d9f5620608f15e6a63aaf Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 23 Aug 2013 22:17:08 -0500 Subject: [PATCH 148/232] DECORATE cleanup - Remove some ExpVal stuff that wasn't used. --- src/thingdef/thingdef_exp.h | 26 -------------------------- src/thingdef/thingdef_type.h | 1 - 2 files changed, 27 deletions(-) diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 0c7cfcfa7..1b3e5d854 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -164,36 +164,10 @@ struct ExpVal return (Type == VAL_Int || Type == VAL_Sound) ? !!Int : Type == VAL_Float? Float!=0. : false; } - template<class T> T *GetPointer() const - { - return Type == VAL_Object || Type == VAL_Pointer? (T*)pointer : NULL; - } - - FSoundID GetSoundID() const - { - return Type == VAL_Sound? Int : 0; - } - - int GetColor() const - { - return Type == VAL_Color? Int : 0; - } - FName GetName() const { return Type == VAL_Name? ENamedName(Int) : NAME_None; } - - FState *GetState() const - { - return Type == VAL_State? (FState*)pointer : NULL; - } - - const PClass *GetClass() const - { - return Type == VAL_Class? (const PClass *)pointer : NULL; - } - }; struct ExpEmit diff --git a/src/thingdef/thingdef_type.h b/src/thingdef/thingdef_type.h index a89c80749..706b2ba7a 100644 --- a/src/thingdef/thingdef_type.h +++ b/src/thingdef/thingdef_type.h @@ -14,7 +14,6 @@ enum ExpValType VAL_Array, // Array (very limited right now) VAL_Object, // Object reference VAL_Class, // Class reference - VAL_Pointer, // Dereferenced variable (only used for addressing arrays for now.) VAL_Sound, // Sound identifier. Internally it's an int. VAL_Name, // A Name VAL_String, // A string From 80daf736ecced4bd615747630abdfc2fd3cfb75c Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 24 Aug 2013 20:28:26 -0500 Subject: [PATCH 149/232] Accept enums and structs defined at global scope --- src/zscript/zcc-parse.lemon | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index bb85f3016..2d6eb131f 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -79,6 +79,8 @@ translation_unit(X) ::= error. { X = NULL; } %type external_declaration {ZCC_TreeNode *} external_declaration(X) ::= class_definition(A). { X = A; } +external_declaration(X) ::= struct_def(A). { X = A; } +external_declaration(X) ::= enum_def(A). { X = A; } /* Optional bits. */ opt_semicolon ::= . From 064710422ba641c74b6d8692b239765f664ecc5a Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 24 Aug 2013 20:32:59 -0500 Subject: [PATCH 150/232] Accept empty struct and enum definitions (useless as they may be) --- src/zscript/zcc-parse.lemon | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index 2d6eb131f..bfb5a8e12 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -191,10 +191,11 @@ class_member(X) ::= const_def(A). { X = A; } /*----- Struct Definition -----*/ /* Structs can define variables and enums. */ +%type opt_struct_body{ZCC_TreeNode *} %type struct_body{ZCC_TreeNode *} %type struct_member{ZCC_TreeNode *} -struct_def(X) ::= STRUCT IDENTIFIER(A) LBRACE struct_body(B) RBRACE opt_semicolon. +struct_def(X) ::= STRUCT IDENTIFIER(A) LBRACE opt_struct_body(B) RBRACE opt_semicolon. { NEW_AST_NODE(Struct,def); def->StructName = A.Name(); @@ -202,6 +203,9 @@ struct_def(X) ::= STRUCT IDENTIFIER(A) LBRACE struct_body(B) RBRACE opt_semicolo X = def; } +opt_struct_body(X) ::= . { X = NULL; } +opt_struct_body(X) ::= struct_body(A). { X = A; } + struct_body(X) ::= error. { X = NULL; } struct_body(X) ::= struct_member(A). { X = A; } struct_body(X) ::= struct_member(A) struct_body(B). { X = A; A->AppendSibling(B); } @@ -215,9 +219,10 @@ struct_member(X) ::= enum_def(A). { X = A; } %type enum_type {EZCCBuiltinType} %type enum_list {ZCC_EnumNode *} +%type opt_enum_list {ZCC_EnumNode *} %type enumerator {ZCC_EnumNode *} -enum_def(X) ::= ENUM IDENTIFIER(A) enum_type(B) LBRACE enum_list(C) opt_comma RBRACE opt_semicolon. +enum_def(X) ::= ENUM IDENTIFIER(A) enum_type(B) LBRACE opt_enum_list(C) RBRACE opt_semicolon. { NEW_AST_NODE(Enum,def); def->EnumName = A.Name(); @@ -233,6 +238,9 @@ enum_list(X) ::= error. { X = NULL; } enum_list(X) ::= enumerator(A). { X = A; } enum_list(X) ::= enum_list(A) COMMA enumerator(B). { X = A; A->AppendSibling(B); } +opt_enum_list(X) ::= . { X = NULL; } +opt_enum_list(X) ::= enum_list(A) opt_comma. { X = A; } + enumerator(X) ::= IDENTIFIER(A). { NEW_AST_NODE(EnumNode,node); From 5e0e74a47d71473be8c28b335fc14502eb37f9d4 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 28 Aug 2013 22:35:29 -0500 Subject: [PATCH 151/232] Fix incorrect comment --- src/sc_man.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sc_man.cpp b/src/sc_man.cpp index 6b275a822..de668ee42 100644 --- a/src/sc_man.cpp +++ b/src/sc_man.cpp @@ -895,7 +895,7 @@ FString FScanner::TokenName (int token, const char *string) //========================================================================== // -// FScanner::ScriptError +// FScanner::GetMessageLine // //========================================================================== From 2823ea5de34710efa300aea795af9115434b18ef Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 28 Aug 2013 22:59:03 -0500 Subject: [PATCH 152/232] Annote AST nodes with source information --- src/zscript/zcc-parse.lemon | 342 +++++++++++++++++++----------------- src/zscript/zcc_parser.cpp | 1 + src/zscript/zcc_parser.h | 17 +- 3 files changed, 196 insertions(+), 164 deletions(-) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index bfb5a8e12..6bd5cdf95 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -1,11 +1,34 @@ %include { // Allocates a new AST node off the parse state's arena. -#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 +#define NEW_AST_NODE(type,name,tok) \ + ZCC_##type *name = static_cast<ZCC_##type *>(InitNode(sizeof(ZCC_##type), AST_##type, stat)); \ + SetNodeLine(name, tok) + +static ZCC_TreeNode *InitNode(size_t size, EZCCTreeNodeType type, ZCCParseState *stat) +{ + ZCC_TreeNode *node = (ZCC_TreeNode *)stat->SyntaxArena.Alloc(size); + node->SiblingNext = node; + node->SiblingPrev = node; + node->NodeType = type; + node->SourceName = stat->Strings.Alloc(stat->sc.ScriptName); + return node; +} + +static void SetNodeLine(ZCC_TreeNode *name, ZCCToken &tok) +{ + name->SourceLoc = tok.SourceLoc; +} + +static void SetNodeLine(ZCC_TreeNode *name, ZCC_TreeNode *node) +{ + name->SourceLoc = node->SourceLoc; +} + +static void SetNodeLine(ZCC_TreeNode *name, int line) +{ + name->SourceLoc = line; +} // If a is non-null, appends b to a. Otherwise, sets a to b. #define SAFE_APPEND(a,b) \ @@ -115,9 +138,9 @@ class_definition(X) ::= class_head(A) class_body(B). X = A; } -class_head(X) ::= CLASS dottable_id(A) class_ancestry(B) class_flags(C). +class_head(X) ::= CLASS(T) dottable_id(A) class_ancestry(B) class_flags(C). { - NEW_AST_NODE(Class,head); + NEW_AST_NODE(Class,head,T); head->ClassName = A; head->ParentName = B; head->Flags = C.Flags; @@ -148,13 +171,13 @@ class_flags(X) ::= class_flags(A) REPLACES dottable_id(B). { X.Flags = A.Flags; dottable_id(X) ::= IDENTIFIER(A). { - NEW_AST_NODE(Identifier,id); + NEW_AST_NODE(Identifier,id,A); id->Id = A.Name(); X = id; } dottable_id(X) ::= dottable_id(A) DOT IDENTIFIER(B). { - NEW_AST_NODE(Identifier,id2); + NEW_AST_NODE(Identifier,id2,A); id2->Id = B.Name(); A->AppendSibling(id2); X = A; @@ -195,9 +218,9 @@ class_member(X) ::= const_def(A). { X = A; } %type struct_body{ZCC_TreeNode *} %type struct_member{ZCC_TreeNode *} -struct_def(X) ::= STRUCT IDENTIFIER(A) LBRACE opt_struct_body(B) RBRACE opt_semicolon. +struct_def(X) ::= STRUCT(T) IDENTIFIER(A) LBRACE opt_struct_body(B) RBRACE opt_semicolon. { - NEW_AST_NODE(Struct,def); + NEW_AST_NODE(Struct,def,T); def->StructName = A.Name(); def->Body = B; X = def; @@ -217,21 +240,20 @@ struct_member(X) ::= enum_def(A). { X = A; } /*----- Enum Definition -----*/ /* Enumerators are lists of named integers. */ -%type enum_type {EZCCBuiltinType} %type enum_list {ZCC_EnumNode *} %type opt_enum_list {ZCC_EnumNode *} %type enumerator {ZCC_EnumNode *} -enum_def(X) ::= ENUM IDENTIFIER(A) enum_type(B) LBRACE opt_enum_list(C) RBRACE opt_semicolon. +enum_def(X) ::= ENUM(T) IDENTIFIER(A) enum_type(B) LBRACE opt_enum_list(C) RBRACE opt_semicolon. { - NEW_AST_NODE(Enum,def); + NEW_AST_NODE(Enum,def,T); def->EnumName = A.Name(); - def->EnumType = B; + def->EnumType = (EZCCBuiltinType)B.Int; def->Elements = C; X = def; } -enum_type(X) ::= . { X = ZCC_IntAuto; } +enum_type(X) ::= . { X.Int = ZCC_IntAuto; X.SourceLoc = stat->sc.GetMessageLine(); } enum_type(X) ::= COLON int_type(A). { X = A; } enum_list(X) ::= error. { X = NULL; } @@ -243,14 +265,14 @@ opt_enum_list(X) ::= enum_list(A) opt_comma. { X = A; } enumerator(X) ::= IDENTIFIER(A). { - NEW_AST_NODE(EnumNode,node); + NEW_AST_NODE(EnumNode,node,A); node->ElemName = A.Name(); node->ElemValue = NULL; X = node; } enumerator(X) ::= IDENTIFIER(A) EQ expr(B). /* Expression must be constant. */ { - NEW_AST_NODE(EnumNode,node); + NEW_AST_NODE(EnumNode,node,A); node->ElemName = A.Name(); node->ElemValue = B; X = node; @@ -276,9 +298,9 @@ enumerator(X) ::= IDENTIFIER(A) EQ expr(B). /* Expression must be constant. */ } %type state_opts {StateOpts} -states_def(X) ::= STATES scanner_mode LBRACE states_body(A) RBRACE. +states_def(X) ::= STATES(T) scanner_mode LBRACE states_body(A) RBRACE. { - NEW_AST_NODE(States,def); + NEW_AST_NODE(States,def,T); def->Body = A; X = def; } @@ -304,20 +326,20 @@ states_body(X) ::= states_body(A) state_flow(B). { SAFE_APPEND(A,B); X = A; } state_label(X) ::= NWS(A) COLON. { - NEW_AST_NODE(StateLabel, label); + NEW_AST_NODE(StateLabel, label, A); label->Label = A.Name(); X = label; } state_flow(X) ::= state_flow_type(A) scanner_mode SEMICOLON. { X = A; } -state_flow_type(X) ::= STOP. { NEW_AST_NODE(StateStop, flow); X = flow; } -state_flow_type(X) ::= WAIT. { NEW_AST_NODE(StateWait, flow); X = flow; } -state_flow_type(X) ::= FAIL. { NEW_AST_NODE(StateFail, flow); X = flow; } -state_flow_type(X) ::= LOOP. { NEW_AST_NODE(StateLoop, flow); X = flow; } -state_flow_type(X) ::= GOTO dottable_id(A) state_goto_offset(B). +state_flow_type(X) ::= STOP(A). { NEW_AST_NODE(StateStop, flow, A); X = flow; } +state_flow_type(X) ::= WAIT(A). { NEW_AST_NODE(StateWait, flow, A); X = flow; } +state_flow_type(X) ::= FAIL(A). { NEW_AST_NODE(StateFail, flow, A); X = flow; } +state_flow_type(X) ::= LOOP(A). { NEW_AST_NODE(StateLoop, flow, A); X = flow; } +state_flow_type(X) ::= GOTO(T) dottable_id(A) state_goto_offset(B). { - NEW_AST_NODE(StateGoto, flow); + NEW_AST_NODE(StateGoto, flow, T); flow->Label = A; flow->Offset = B; X = flow; @@ -328,7 +350,7 @@ state_goto_offset(X) ::= PLUS expr(A). { X = A; } /* Must evaluate to a non-nega state_line(X) ::= NWS(A) NWS(B) expr state_opts(C) state_action(D). { - NEW_AST_NODE(StateLine, line); + NEW_AST_NODE(StateLine, line, A); const char *sprite = FName(A.Name()).GetChars(); if (strlen(sprite) != 4) { @@ -361,8 +383,8 @@ state_action(X) ::= state_call(A) scanner_mode SEMICOLON. { X = A; } state_call(X) ::= . { X = NULL; } state_call(X) ::= IDENTIFIER(A) state_call_params(B). { - NEW_AST_NODE(ExprFuncCall, expr); - NEW_AST_NODE(ExprID, func); + NEW_AST_NODE(ExprFuncCall, expr, A); + NEW_AST_NODE(ExprID, func, A); func->Operation = PEX_ID; func->Identifier = A.Name(); @@ -380,37 +402,34 @@ state_call_params(X) ::= LPAREN func_expr_list(A) RPAREN. { X = A; } default_def(X) ::= DEFAULT compound_statement(A). { X = A; } /* Type names */ -%type int_type {EZCCBuiltinType} %type type_name {ZCC_BasicType *} -%type type_name1 {EZCCBuiltinType} -%type vector_size {EZCCBuiltinType} -int_type(X) ::= SBYTE. { X = ZCC_SInt8; } -int_type(X) ::= BYTE. { X = ZCC_UInt8; } -int_type(X) ::= SHORT. { X = ZCC_SInt16; } -int_type(X) ::= USHORT. { X = ZCC_UInt16; } -int_type(X) ::= INT. { X = ZCC_SInt32; } -int_type(X) ::= UINT. { X = ZCC_UInt32; } +int_type(X) ::= SBYTE(T). { X.Int = ZCC_SInt8; X.SourceLoc = T.SourceLoc; } +int_type(X) ::= BYTE(T). { X.Int = ZCC_UInt8; X.SourceLoc = T.SourceLoc; } +int_type(X) ::= SHORT(T). { X.Int = ZCC_SInt16; X.SourceLoc = T.SourceLoc; } +int_type(X) ::= USHORT(T). { X.Int = ZCC_UInt16; X.SourceLoc = T.SourceLoc; } +int_type(X) ::= INT(T). { X.Int = ZCC_SInt32; X.SourceLoc = T.SourceLoc; } +int_type(X) ::= UINT(T). { X.Int = ZCC_UInt32; X.SourceLoc = T.SourceLoc; } -type_name1(X) ::= BOOL. { X = ZCC_Bool; } +type_name1(X) ::= BOOL(T). { X.Int = ZCC_Bool; X.SourceLoc = T.SourceLoc; } type_name1(X) ::= int_type(A). { X = A; } -type_name1(X) ::= FLOAT. { X = ZCC_FloatAuto; } -type_name1(X) ::= DOUBLE. { X = ZCC_Float64; } -type_name1(X) ::= STRING. { X = ZCC_String; } -type_name1(X) ::= VECTOR vector_size(A). { X = A; } -type_name1(X) ::= NAME. { X = ZCC_Name; } +type_name1(X) ::= FLOAT(T). { X.Int = ZCC_FloatAuto; X.SourceLoc = T.SourceLoc; } +type_name1(X) ::= DOUBLE(T). { X.Int = ZCC_Float64; X.SourceLoc = T.SourceLoc; } +type_name1(X) ::= STRING(T). { X.Int = ZCC_String; X.SourceLoc = T.SourceLoc; } +type_name1(X) ::= VECTOR(T) vector_size(A). { X.Int = A.Int; X.SourceLoc = T.SourceLoc; } +type_name1(X) ::= NAME(T). { X.Int = ZCC_Name; X.SourceLoc = T.SourceLoc; } type_name(X) ::= type_name1(A). { - NEW_AST_NODE(BasicType, type); - type->Type = A; + NEW_AST_NODE(BasicType, type, A); + type->Type = (EZCCBuiltinType)A.Int; type->UserType = NULL; X = type; } type_name(X) ::= IDENTIFIER(A). /* User-defined type (struct, enum, or class) */ { - NEW_AST_NODE(BasicType, type); - NEW_AST_NODE(Identifier, id); + NEW_AST_NODE(BasicType, type, A); + NEW_AST_NODE(Identifier, id, A); type->Type = ZCC_UserType; type->UserType = id; id->Id = A.Name(); @@ -418,7 +437,7 @@ type_name(X) ::= IDENTIFIER(A). /* User-defined type (struct, enum, or class) } type_name(X) ::= DOT dottable_id(A). { - NEW_AST_NODE(BasicType, type); + NEW_AST_NODE(BasicType, type, A); type->Type = ZCC_UserType; type->UserType = A; X = type; @@ -428,18 +447,19 @@ type_name(X) ::= DOT dottable_id(A). * (Well, actually, I'm not sure if 4D ones are going to happen * straight away.) */ -vector_size(X) ::= . { X = ZCC_Vector3; } +vector_size(X) ::= . { X.Int = ZCC_Vector3; X.SourceLoc = stat->sc.GetMessageLine(); } vector_size(X) ::= LT INTCONST(A) GT. { if (A.Int >= 2 && A.Int <= 4) { - X = EZCCBuiltinType(ZCC_Vector2 + A.Int - 2); + X.Int = ZCC_Vector2 + A.Int - 2; } else { - X = ZCC_Vector3; + X.Int = ZCC_Vector3; stat->sc.ScriptMessage("Invalid vector size %d\n", A.Int); } + X.SourceLoc = A.SourceLoc; } /* Type names can also be used as identifiers in contexts where type names @@ -457,24 +477,24 @@ vector_size(X) ::= LT INTCONST(A) GT. %type array_size{ZCC_Expression *} %type array_size_expr{ZCC_Expression *} -aggregate_type(X) ::= MAP LT type_or_array(A) COMMA type_or_array(B) GT. /* Hash table */ +aggregate_type(X) ::= MAP(T) LT type_or_array(A) COMMA type_or_array(B) GT. /* Hash table */ { - NEW_AST_NODE(MapType,map); + NEW_AST_NODE(MapType,map,T); map->KeyType = A; map->ValueType = B; X = map; } -aggregate_type(X) ::= ARRAY LT type_or_array(A) GT. /* TArray<type> */ +aggregate_type(X) ::= ARRAY(T) LT type_or_array(A) GT. /* TArray<type> */ { - NEW_AST_NODE(DynArrayType,arr); + NEW_AST_NODE(DynArrayType,arr,T); arr->ElementType = A; X = arr; } -aggregate_type(X) ::= CLASS class_restrictor(A). /* class<type> */ +aggregate_type(X) ::= CLASS(T) class_restrictor(A). /* class<type> */ { - NEW_AST_NODE(ClassType,cls); + NEW_AST_NODE(ClassType,cls,T); cls->Restriction = A; X = cls; } @@ -497,7 +517,7 @@ array_size_expr(X) ::= LBRACKET opt_expr(A) RBRACKET. { if (A == NULL) { - NEW_AST_NODE(Expression,nil); + NEW_AST_NODE(Expression,nil,A); nil->Operation = PEX_Nil; X = nil; } @@ -525,6 +545,7 @@ array_size(X) ::= array_size(A) array_size_expr(B). ZCC_CompoundStmt *FuncBody; ENamedName FuncName; int FuncFlags; + int SourceLoc; }; } %type variables_or_function {VarOrFun} @@ -538,20 +559,20 @@ declarator(X) ::= decl_flags(A) type_list_or_void(B) variables_or_function(C). } else if (C.FuncName != NAME_None) { // A function - NEW_AST_NODE(FuncDeclarator, decl); + NEW_AST_NODE(FuncDeclarator, decl, A.SourceLoc); decl->Type = B; decl->Params = C.FuncParams; decl->Name = C.FuncName; - decl->Flags = A | C.FuncFlags; + decl->Flags = A.Int | C.FuncFlags; decl->Body = C.FuncBody; X = decl; } else if (B != NULL && B->SiblingNext == B) { // A variable - NEW_AST_NODE(VarDeclarator, decl); + NEW_AST_NODE(VarDeclarator, decl, A.SourceLoc); decl->Type = B; decl->Names = C.VarNames; - decl->Flags = A; + decl->Flags = A.Int; X = decl; } else @@ -569,10 +590,10 @@ declarator(X) ::= decl_flags(A) type_list_or_void(B) variables_or_function(C). } declarator_no_fun(X) ::= decl_flags(A) type(B) variable_list(C). { - NEW_AST_NODE(VarDeclarator, decl); + NEW_AST_NODE(VarDeclarator, decl, A.SourceLoc ? A.SourceLoc : B->SourceLoc); decl->Type = B; decl->Names = C; - decl->Flags = A; + decl->Flags = A.Int; X = decl; } @@ -583,9 +604,10 @@ variables_or_function(X) ::= IDENTIFIER(A) LPAREN func_params(B) RPAREN func_con fun.VarNames = NULL; fun.FuncParams = B; - fun.FuncFlags = C; + fun.FuncFlags = C.Int; fun.FuncName = A.Name(); fun.FuncBody = D; + fun.SourceLoc = A.SourceLoc; X = fun; } variables_or_function(X) ::= variable_list(A) SEMICOLON. @@ -597,9 +619,10 @@ variables_or_function(X) ::= variable_list(A) SEMICOLON. var.FuncFlags = 0; var.FuncName = NAME_None; var.FuncBody = NULL; + var.SourceLoc = A->SourceLoc; X = var; } -variables_or_function(X) ::= error SEMICOLON. +variables_or_function(X) ::= error SEMICOLON(T). { VarOrFun bad; bad.VarNames = NULL; @@ -607,6 +630,7 @@ variables_or_function(X) ::= error SEMICOLON. bad.FuncFlags = 0; bad.FuncName = NAME_None; bad.FuncBody = NULL; + bad.SourceLoc = T.SourceLoc; X = bad; } @@ -614,19 +638,17 @@ variables_or_function(X) ::= error SEMICOLON. %type variable_name{ZCC_VarName *} %type variable_list{ZCC_VarName *} -%type decl_flags{int} -%type func_const{int} variable_name(X) ::= IDENTIFIER(A). { - NEW_AST_NODE(VarName,var); + NEW_AST_NODE(VarName,var,A); var->Name = ENamedName(A.Int); var->ArraySize = NULL; X = var; } variable_name(X) ::= IDENTIFIER(A) array_size(B). { - NEW_AST_NODE(VarName,var); + NEW_AST_NODE(VarName,var,A); var->Name = ENamedName(A.Int); var->ArraySize = B; X = var; @@ -642,20 +664,20 @@ variable_list(X) ::= variable_list(A) COMMA variable_name(B). X = A; } -decl_flags(X) ::= . { X = 0; } -decl_flags(X) ::= decl_flags(A) NATIVE. { X = A | ZCC_Native; } -decl_flags(X) ::= decl_flags(A) STATIC. { X = A | ZCC_Static; } -decl_flags(X) ::= decl_flags(A) PRIVATE. { X = A | ZCC_Private; } -decl_flags(X) ::= decl_flags(A) PROTECTED. { X = A | ZCC_Protected; } -decl_flags(X) ::= decl_flags(A) LATENT. { X = A | ZCC_Latent; } -decl_flags(X) ::= decl_flags(A) FINAL. { X = A | ZCC_Final; } -decl_flags(X) ::= decl_flags(A) META. { X = A | ZCC_Meta; } -decl_flags(X) ::= decl_flags(A) ACTION. { X = A | ZCC_Action; } -decl_flags(X) ::= decl_flags(A) READONLY. { X = A | ZCC_ReadOnly; } -decl_flags(X) ::= decl_flags(A) DEPRECATED. { X = A | ZCC_Deprecated; } +decl_flags(X) ::= . { X.Int = 0; X.SourceLoc = 0; } +decl_flags(X) ::= decl_flags(A) NATIVE(T). { X.Int = A.Int | ZCC_Native; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +decl_flags(X) ::= decl_flags(A) STATIC(T). { X.Int = A.Int | ZCC_Static; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +decl_flags(X) ::= decl_flags(A) PRIVATE(T). { X.Int = A.Int | ZCC_Private; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +decl_flags(X) ::= decl_flags(A) PROTECTED(T). { X.Int = A.Int | ZCC_Protected; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +decl_flags(X) ::= decl_flags(A) LATENT(T). { X.Int = A.Int | ZCC_Latent; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +decl_flags(X) ::= decl_flags(A) FINAL(T). { X.Int = A.Int | ZCC_Final; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +decl_flags(X) ::= decl_flags(A) META(T). { X.Int = A.Int | ZCC_Meta; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +decl_flags(X) ::= decl_flags(A) ACTION(T). { X.Int = A.Int | ZCC_Action; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +decl_flags(X) ::= decl_flags(A) READONLY(T). { X.Int = A.Int | ZCC_ReadOnly; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +decl_flags(X) ::= decl_flags(A) DEPRECATED(T). { X.Int = A.Int | ZCC_Deprecated; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } -func_const(X) ::= . { X = 0; } -func_const(X) ::= CONST. { X = ZCC_FuncConst; } +func_const(X) ::= . { X.Int = 0; X.SourceLoc = stat->sc.GetMessageLine(); } +func_const(X) ::= CONST(T). { X.Int = ZCC_FuncConst; X.SourceLoc = T.SourceLoc; } opt_func_body(X) ::= SEMICOLON. { X = NULL; } opt_func_body(X) ::= function_body(A). { X = A; } @@ -663,7 +685,6 @@ opt_func_body(X) ::= function_body(A). { X = A; } %type func_params {ZCC_FuncParamDecl *} %type func_param_list {ZCC_FuncParamDecl *} %type func_param {ZCC_FuncParamDecl *} -%type func_param_flags {int} func_params(X) ::= . /* empty */ { X = NULL; } func_params(X) ::= VOID. { X = NULL; } @@ -674,22 +695,22 @@ func_param_list(X) ::= func_param_list(A) COMMA func_param(B). { X = A; A->Appen func_param(X) ::= func_param_flags(A) type(B) IDENTIFIER(C). { - NEW_AST_NODE(FuncParamDecl,parm); + NEW_AST_NODE(FuncParamDecl,parm,A.SourceLoc ? A.SourceLoc : B->SourceLoc); parm->Type = B; parm->Name = C.Name(); - parm->Flags = A; + parm->Flags = A.Int; X = parm; } -func_param_flags(X) ::= . { X = 0; } -func_param_flags(X) ::= func_param_flags(A) IN. { X = A | ZCC_In; } -func_param_flags(X) ::= func_param_flags(A) OUT. { X = A | ZCC_Out; } -func_param_flags(X) ::= func_param_flags(A) OPTIONAL. { X = A | ZCC_Optional; } +func_param_flags(X) ::= . { X.Int = 0; X.SourceLoc = 0; } +func_param_flags(X) ::= func_param_flags(A) IN(T). { X.Int = A.Int | ZCC_In; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +func_param_flags(X) ::= func_param_flags(A) OUT(T). { X.Int = A.Int | ZCC_Out; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +func_param_flags(X) ::= func_param_flags(A) OPTIONAL(T). { X.Int = A.Int | ZCC_Optional; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } /* Like UnrealScript, a constant's type is implied by its value's type. */ -const_def(X) ::= CONST IDENTIFIER(A) EQ expr(B) SEMICOLON. +const_def(X) ::= CONST(T) IDENTIFIER(A) EQ expr(B) SEMICOLON. { - NEW_AST_NODE(ConstantDef,def); + NEW_AST_NODE(ConstantDef,def,T); def->Name = A.Name(); def->Value = B; X = def; @@ -707,22 +728,22 @@ const_def(X) ::= CONST IDENTIFIER(A) EQ expr(B) SEMICOLON. %type constant{ZCC_Expression *} %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 +#define UNARY_EXPR(X,T) NEW_AST_NODE(ExprUnary, expr, X); expr->Operation = T; expr->Operand = X +#define BINARY_EXPR(X,Y,T) NEW_AST_NODE(ExprBinary, expr, X); expr->Operation = T; expr->Left = X; expr->Right = Y } /*----- Primary Expressions -----*/ primary(X) ::= IDENTIFIER(A). { - NEW_AST_NODE(ExprID, expr); + NEW_AST_NODE(ExprID, expr, A); expr->Operation = PEX_ID; expr->Identifier = A.Name(); X = expr; } -primary(X) ::= SUPER. +primary(X) ::= SUPER(T). { - NEW_AST_NODE(Expression, expr); + NEW_AST_NODE(Expression, expr, T); expr->Operation = PEX_Super; X = expr; } @@ -730,9 +751,9 @@ primary(X) ::= constant(A). { X = A; } -primary(X) ::= SELF. +primary(X) ::= SELF(T). { - NEW_AST_NODE(Expression, expr); + NEW_AST_NODE(Expression, expr, T); expr->Operation = PEX_Self; X = expr; } @@ -743,7 +764,7 @@ primary(X) ::= LPAREN expr(A) RPAREN. primary ::= LPAREN error RPAREN. primary(X) ::= primary(A) LPAREN func_expr_list(B) RPAREN. [DOT] // Function call { - NEW_AST_NODE(ExprFuncCall, expr); + NEW_AST_NODE(ExprFuncCall, expr, A); expr->Operation = PEX_FuncCall; expr->Function = A; expr->Parameters = B; @@ -751,7 +772,7 @@ primary(X) ::= primary(A) LPAREN func_expr_list(B) RPAREN. [DOT] // Function ca } primary(X) ::= primary(A) LBRACKET expr(B) RBRACKET. [DOT] // Array access { - NEW_AST_NODE(ExprBinary, expr); + NEW_AST_NODE(ExprBinary, expr, B); expr->Operation = PEX_ArrayAccess; expr->Left = A; expr->Right = B; @@ -759,7 +780,7 @@ primary(X) ::= primary(A) LBRACKET expr(B) RBRACKET. [DOT] // Array access } primary(X) ::= primary(A) DOT IDENTIFIER(B). // Member access { - NEW_AST_NODE(ExprMemberAccess, expr); + NEW_AST_NODE(ExprMemberAccess, expr, B); expr->Operation = PEX_MemberAccess; expr->Left = A; expr->Right = ENamedName(B.Int); @@ -979,7 +1000,7 @@ expr(X) ::= expr(A) SCOPE expr(B). expr(X) ::= expr(A) QUESTION expr(B) COLON expr(C). { - NEW_AST_NODE(ExprTrinary, expr); + NEW_AST_NODE(ExprTrinary, expr, A); expr->Operation = PEX_Trinary; expr->Test = A; expr->Left = B; @@ -1014,19 +1035,19 @@ func_expr_list(X) ::= func_expr_item(A). { X = A; } -func_expr_list(X) ::= func_expr_list(A) COMMA func_expr_item(B). +func_expr_list(X) ::= func_expr_list(A) COMMA(T) func_expr_item(B). { // Omitted parameters still need to appear as nodes in the list. if (A == NULL) { - NEW_AST_NODE(FuncParm,nil_a); + NEW_AST_NODE(FuncParm,nil_a,T); nil_a->Value = NULL; nil_a->Label = NAME_None; A = nil_a; } if (B == NULL) { - NEW_AST_NODE(FuncParm,nil_b); + NEW_AST_NODE(FuncParm,nil_b,T); nil_b->Value = NULL; nil_b->Label = NAME_None; B = nil_b; @@ -1046,14 +1067,14 @@ func_expr_item(X) ::= named_expr(A). named_expr(X) ::= IDENTIFIER(A) COLON expr(B). { - NEW_AST_NODE(FuncParm, parm); + NEW_AST_NODE(FuncParm, parm, A); parm->Value = B; parm->Label = ENamedName(A.Int); X = parm; } named_expr(X) ::= expr(B). { - NEW_AST_NODE(FuncParm, parm); + NEW_AST_NODE(FuncParm, parm, B); parm->Value = B; parm->Label = NAME_None; X = parm; @@ -1066,14 +1087,14 @@ named_expr(X) ::= expr(B). string_constant(X) ::= STRCONST(A). { - NEW_AST_NODE(ExprString, strconst); + NEW_AST_NODE(ExprString, strconst, A); strconst->Operation = PEX_StringConst; strconst->Value = A.String; X = strconst; } string_constant(X) ::= string_constant(A) STRCONST(B). { - NEW_AST_NODE(ExprString, strconst); + NEW_AST_NODE(ExprString, strconst, A); strconst->Operation = PEX_StringConst; strconst->Value = stat->Strings.Alloc(*(A->Value) + *(B.String)); X = strconst; @@ -1085,14 +1106,14 @@ constant(X) ::= string_constant(A). } constant(X) ::= INTCONST(A). { - NEW_AST_NODE(ExprInt, intconst); + NEW_AST_NODE(ExprInt, intconst, A); intconst->Operation = PEX_IntConst; intconst->Value = A.Int; X = intconst; } constant(X) ::= FLOATCONST(A). { - NEW_AST_NODE(ExprFloat, floatconst); + NEW_AST_NODE(ExprFloat, floatconst, A); floatconst->Operation = PEX_FloatConst; floatconst->Value = A.Float; X = floatconst; @@ -1118,25 +1139,25 @@ statement(X) ::= error SEMICOLON. { X = NULL; } %type jump_statement{ZCC_Statement *} -jump_statement(A) ::= CONTINUE SEMICOLON. +jump_statement(A) ::= CONTINUE(T) SEMICOLON. { - NEW_AST_NODE(ContinueStmt, stmt); + NEW_AST_NODE(ContinueStmt, stmt, T); A = stmt; } -jump_statement(A) ::= BREAK SEMICOLON. +jump_statement(A) ::= BREAK(T) SEMICOLON. { - NEW_AST_NODE(BreakStmt, stmt); + NEW_AST_NODE(BreakStmt, stmt, T); A = stmt; } -jump_statement(A) ::= RETURN SEMICOLON. +jump_statement(A) ::= RETURN(T) SEMICOLON. { - NEW_AST_NODE(ReturnStmt, stmt); + NEW_AST_NODE(ReturnStmt, stmt, T); stmt->Values = NULL; A = stmt; } -jump_statement(A) ::= RETURN expr_list(X) SEMICOLON. +jump_statement(A) ::= RETURN(T) expr_list(X) SEMICOLON. { - NEW_AST_NODE(ReturnStmt, stmt); + NEW_AST_NODE(ReturnStmt, stmt, T); stmt->Values = X; A = stmt; } @@ -1146,21 +1167,21 @@ jump_statement(A) ::= RETURN expr_list(X) SEMICOLON. %type compound_statement{ZCC_CompoundStmt *} %type statement_list{ZCC_Statement *} -compound_statement(X) ::= LBRACE RBRACE. +compound_statement(X) ::= LBRACE(T) RBRACE. { - NEW_AST_NODE(CompoundStmt,stmt); + NEW_AST_NODE(CompoundStmt,stmt,T); stmt->Content = NULL; X = stmt; } -compound_statement(X) ::= LBRACE statement_list(A) RBRACE. +compound_statement(X) ::= LBRACE(T) statement_list(A) RBRACE. { - NEW_AST_NODE(CompoundStmt,stmt); + NEW_AST_NODE(CompoundStmt,stmt,T); stmt->Content = A; X = stmt; } -compound_statement(X) ::= LBRACE error RBRACE. +compound_statement(X) ::= LBRACE(T) error RBRACE. { - NEW_AST_NODE(CompoundStmt,stmt); + NEW_AST_NODE(CompoundStmt,stmt,T); stmt->Content = NULL; X = stmt; } @@ -1181,7 +1202,7 @@ statement_list(X) ::= statement_list(A) statement(B). expression_statement(X) ::= expr(A). { - NEW_AST_NODE(ExpressionStmt, stmt); + NEW_AST_NODE(ExpressionStmt, stmt, A); stmt->Expression = A; X = stmt; } @@ -1193,7 +1214,7 @@ expression_statement(X) ::= expr(A). // while/until (expr) statement iteration_statement(X) ::= while_or_until(TY) LPAREN expr(EX) RPAREN statement(ST). { - NEW_AST_NODE(IterationStmt, iter); + NEW_AST_NODE(IterationStmt, iter, TY); if (TY.Int == ZCC_UNTIL) { // Negate the loop condition UNARY_EXPR(EX,PEX_BoolNot); @@ -1209,9 +1230,9 @@ iteration_statement(X) ::= while_or_until(TY) LPAREN expr(EX) RPAREN statement(S X = iter; } // do statement while/until (expr) -iteration_statement(X) ::= DO statement(ST) while_or_until(TY) LPAREN expr(EX) RPAREN. +iteration_statement(X) ::= DO(T) statement(ST) while_or_until(TY) LPAREN expr(EX) RPAREN. { - NEW_AST_NODE(IterationStmt, iter); + NEW_AST_NODE(IterationStmt, iter, T); if (TY.Int == ZCC_UNTIL) { // Negate the loop condition UNARY_EXPR(EX,PEX_BoolNot); @@ -1227,9 +1248,9 @@ iteration_statement(X) ::= DO statement(ST) while_or_until(TY) LPAREN expr(EX) R 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). +iteration_statement(X) ::= FOR(T) LPAREN for_init(IN) SEMICOLON opt_expr(EX) SEMICOLON for_bump(DO) RPAREN statement(ST). { - NEW_AST_NODE(IterationStmt, iter); + NEW_AST_NODE(IterationStmt, iter, T); iter->LoopCondition = EX; iter->LoopStatement = ST; iter->LoopBumper = DO; @@ -1239,18 +1260,20 @@ iteration_statement(X) ::= FOR LPAREN for_init(IN) SEMICOLON opt_expr(EX) SEMICO SAFE_APPEND(IN, iter); // And the whole thing gets wrapped inside a compound statement in case the loop // initializer defined any variables. - NEW_AST_NODE(CompoundStmt, wrap); + NEW_AST_NODE(CompoundStmt, wrap, T); wrap->Content = IN; X = wrap; } -while_or_until(X) ::= WHILE. +while_or_until(X) ::= WHILE(T). { X.Int = ZCC_WHILE; + X.SourceLoc = T.SourceLoc; } -while_or_until(X) ::= UNTIL. +while_or_until(X) ::= UNTIL(T). { X.Int = ZCC_UNTIL; + X.SourceLoc = T.SourceLoc; } %type for_init{ZCC_Statement *} @@ -1283,9 +1306,9 @@ selection_statement(X) ::= if_front(A) ELSE statement(B). [ELSE] X = A; } -if_front(X) ::= IF LPAREN expr(A) RPAREN statement(B). +if_front(X) ::= IF(T) LPAREN expr(A) RPAREN statement(B). { - NEW_AST_NODE(IfStmt,stmt); + NEW_AST_NODE(IfStmt,stmt,T); stmt->Condition = A; stmt->TruePath = B; stmt->FalsePath = NULL; @@ -1294,9 +1317,9 @@ if_front(X) ::= IF LPAREN expr(A) RPAREN statement(B). /*----- Switch Statements -----*/ -selection_statement(X) ::= SWITCH LPAREN expr(A) RPAREN statement(B). +selection_statement(X) ::= SWITCH(T) LPAREN expr(A) RPAREN statement(B). { - NEW_AST_NODE(SwitchStmt,stmt); + NEW_AST_NODE(SwitchStmt,stmt,T); stmt->Condition = A; stmt->Content = B; X = stmt; @@ -1306,15 +1329,15 @@ selection_statement(X) ::= SWITCH LPAREN expr(A) RPAREN statement(B). %type labeled_statement{ZCC_CaseStmt *} -labeled_statement(X) ::= CASE expr(A) COLON. +labeled_statement(X) ::= CASE(T) expr(A) COLON. { - NEW_AST_NODE(CaseStmt,stmt); + NEW_AST_NODE(CaseStmt,stmt,T); stmt->Condition = A; X = stmt; } -labeled_statement(X) ::= DEFAULT COLON. +labeled_statement(X) ::= DEFAULT(T) COLON. { - NEW_AST_NODE(CaseStmt,stmt); + NEW_AST_NODE(CaseStmt,stmt,T); stmt->Condition = NULL; X = stmt; } @@ -1322,28 +1345,27 @@ labeled_statement(X) ::= DEFAULT COLON. /*----- Assignment Statements -----*/ %type assign_statement{ZCC_AssignStmt *} -%type assign_op{int} assign_statement(X) ::= expr_list(A) assign_op(OP) expr_list(B). [EQ] { - NEW_AST_NODE(AssignStmt,stmt); - stmt->AssignOp = OP; + NEW_AST_NODE(AssignStmt,stmt,OP); + stmt->AssignOp = OP.Int; stmt->Dests = A; stmt->Sources = B; X = stmt; } -assign_op(X) ::= EQ. { X = ZCC_EQ; } -assign_op(X) ::= MULEQ. { X = ZCC_MULEQ; } -assign_op(X) ::= DIVEQ. { X = ZCC_DIVEQ; } -assign_op(X) ::= MODEQ. { X = ZCC_MODEQ; } -assign_op(X) ::= ADDEQ. { X = ZCC_ADDEQ; } -assign_op(X) ::= SUBEQ. { X = ZCC_SUBEQ; } -assign_op(X) ::= LSHEQ. { X = ZCC_LSHEQ; } -assign_op(X) ::= RSHEQ. { X = ZCC_RSHEQ; } -assign_op(X) ::= ANDEQ. { X = ZCC_ANDEQ; } -assign_op(X) ::= OREQ. { X = ZCC_OREQ; } -assign_op(X) ::= XOREQ. { X = ZCC_XOREQ; } +assign_op(X) ::= EQ(T). { X.Int = ZCC_EQ; X.SourceLoc = T.SourceLoc; } +assign_op(X) ::= MULEQ(T). { X.Int = ZCC_MULEQ; X.SourceLoc = T.SourceLoc; } +assign_op(X) ::= DIVEQ(T). { X.Int = ZCC_DIVEQ; X.SourceLoc = T.SourceLoc; } +assign_op(X) ::= MODEQ(T). { X.Int = ZCC_MODEQ; X.SourceLoc = T.SourceLoc; } +assign_op(X) ::= ADDEQ(T). { X.Int = ZCC_ADDEQ; X.SourceLoc = T.SourceLoc; } +assign_op(X) ::= SUBEQ(T). { X.Int = ZCC_SUBEQ; X.SourceLoc = T.SourceLoc; } +assign_op(X) ::= LSHEQ(T). { X.Int = ZCC_LSHEQ; X.SourceLoc = T.SourceLoc; } +assign_op(X) ::= RSHEQ(T). { X.Int = ZCC_RSHEQ; X.SourceLoc = T.SourceLoc; } +assign_op(X) ::= ANDEQ(T). { X.Int = ZCC_ANDEQ; X.SourceLoc = T.SourceLoc; } +assign_op(X) ::= OREQ(T). { X.Int = ZCC_OREQ; X.SourceLoc = T.SourceLoc; } +assign_op(X) ::= XOREQ(T). { X.Int = ZCC_XOREQ; X.SourceLoc = T.SourceLoc; } /*----- Local Variable Definition "Statements" -----*/ @@ -1351,7 +1373,7 @@ assign_op(X) ::= XOREQ. { X = ZCC_XOREQ; } local_var(X) ::= type(A) variable_list(B) var_init(C). { - NEW_AST_NODE(LocalVarStmt,vardef); + NEW_AST_NODE(LocalVarStmt,vardef,A); vardef->Type = A; vardef->Vars = B; vardef->Inits = C; diff --git a/src/zscript/zcc_parser.cpp b/src/zscript/zcc_parser.cpp index ecf70b678..73301e6b5 100644 --- a/src/zscript/zcc_parser.cpp +++ b/src/zscript/zcc_parser.cpp @@ -186,6 +186,7 @@ static void DoParse(const char *filename) while (sc.GetToken()) { + value.SourceLoc = sc.GetMessageLine(); if (sc.TokenType == TK_StringConst) { value.String = state.Strings.Alloc(sc.String, sc.StringLen); diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index a1f093482..9ee33ab08 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -11,11 +11,15 @@ struct ZCCParseState struct ZCC_TreeNode *TopNode; }; -union ZCCToken +struct ZCCToken { - int Int; - double Float; - FString *String; + union + { + int Int; + double Float; + FString *String; + }; + int SourceLoc; ENamedName Name() { return ENamedName(Int); } }; @@ -195,6 +199,11 @@ struct ZCC_TreeNode ZCC_TreeNode *SiblingNext; ZCC_TreeNode *SiblingPrev; + // can't use FScriptPosition, because the string wouldn't have a chance to + // destruct if we did that. + FString *SourceName; + int SourceLoc; + // Node type is one of the node types above, which corresponds with // one of the structures below. EZCCTreeNodeType NodeType; From 6584819d01b2cfe23cfaaf1ac04ece53d7426bd8 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 7 Sep 2013 20:35:46 -0500 Subject: [PATCH 153/232] Use PType for typing things in PSymbolConst. --- src/dobjtype.h | 2 +- src/thingdef/thingdef_expression.cpp | 15 +++++++-------- src/thingdef/thingdef_parse.cpp | 6 +++--- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/dobjtype.h b/src/dobjtype.h index dad47d44c..56ae1b6de 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -38,7 +38,7 @@ class PSymbolConst : public PSymbol { DECLARE_CLASS(PSymbolConst, PSymbol); public: - int ValueType; + class PType *ValueType; union { int Value; diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index d5fd9b0d2..1f5d48ab5 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -297,17 +297,16 @@ FxExpression *FxConstant::MakeConstant(PSymbol *sym, const FScriptPosition &pos) PSymbolConst *csym = dyn_cast<PSymbolConst>(sym); if (csym != NULL) { - switch(csym->ValueType) + if (csym->ValueType->IsA(RUNTIME_CLASS(PInt))) { - case VAL_Int: x = new FxConstant(csym->Value, pos); - break; - - case VAL_Float: + } + else if (csym->ValueType->IsA(RUNTIME_CLASS(PFloat))) + { x = new FxConstant(csym->Float, pos); - break; - - default: + } + else + { pos.Message(MSG_ERROR, "Invalid constant '%s'\n", csym->SymbolName.GetChars()); return NULL; } diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 55d43b535..db8238d1c 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -205,12 +205,12 @@ static void ParseConstant (FScanner &sc, PSymbolTable *symt, PClassActor *cls) PSymbolConst *sym = new PSymbolConst(symname); if (type == TK_Int) { - sym->ValueType = VAL_Int; + sym->ValueType = TypeSInt32; sym->Value = val.GetInt(); } else { - sym->ValueType = VAL_Float; + sym->ValueType = TypeFloat64; sym->Float = val.GetFloat(); } if (symt->AddSymbol (sym) == NULL) @@ -261,7 +261,7 @@ static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClassActor *cls) delete expr; } PSymbolConst *sym = new PSymbolConst(symname); - sym->ValueType = VAL_Int; + sym->ValueType = TypeSInt32; sym->Value = currvalue; if (symt->AddSymbol (sym) == NULL) { From f9f8d1e79b63743085e7c57450e63dca2dd4bd3f Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 10 Sep 2013 20:50:21 -0500 Subject: [PATCH 154/232] Add a type field for ZCC expressions. - Constants can fill out the type field right away. Other expressions will need to wait until a later pass, after names have been resolved, so they get initialized to NULL. --- src/zscript/zcc-parse.lemon | 16 ++++++++++++++-- src/zscript/zcc_parser.h | 1 + 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index 6bd5cdf95..3384bab03 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -519,6 +519,7 @@ array_size_expr(X) ::= LBRACKET opt_expr(A) RBRACKET. { NEW_AST_NODE(Expression,nil,A); nil->Operation = PEX_Nil; + nil->Type = NULL; X = nil; } else @@ -728,8 +729,8 @@ const_def(X) ::= CONST(T) IDENTIFIER(A) EQ expr(B) SEMICOLON. %type constant{ZCC_Expression *} %include { -#define UNARY_EXPR(X,T) NEW_AST_NODE(ExprUnary, expr, X); expr->Operation = T; expr->Operand = X -#define BINARY_EXPR(X,Y,T) NEW_AST_NODE(ExprBinary, expr, X); expr->Operation = T; expr->Left = X; expr->Right = Y +#define UNARY_EXPR(X,T) NEW_AST_NODE(ExprUnary, expr, X); expr->Operation = T; expr->Operand = X; expr->Type = NULL +#define BINARY_EXPR(X,Y,T) NEW_AST_NODE(ExprBinary, expr, X); expr->Operation = T; expr->Type = NULL; expr->Left = X; expr->Right = Y } /*----- Primary Expressions -----*/ @@ -739,12 +740,14 @@ primary(X) ::= IDENTIFIER(A). NEW_AST_NODE(ExprID, expr, A); expr->Operation = PEX_ID; expr->Identifier = A.Name(); + expr->Type = NULL; X = expr; } primary(X) ::= SUPER(T). { NEW_AST_NODE(Expression, expr, T); expr->Operation = PEX_Super; + expr->Type = NULL; X = expr; } primary(X) ::= constant(A). @@ -755,6 +758,7 @@ primary(X) ::= SELF(T). { NEW_AST_NODE(Expression, expr, T); expr->Operation = PEX_Self; + expr->Type = NULL; X = expr; } primary(X) ::= LPAREN expr(A) RPAREN. @@ -766,6 +770,7 @@ primary(X) ::= primary(A) LPAREN func_expr_list(B) RPAREN. [DOT] // Function ca { NEW_AST_NODE(ExprFuncCall, expr, A); expr->Operation = PEX_FuncCall; + expr->Type = NULL; expr->Function = A; expr->Parameters = B; X = expr; @@ -774,6 +779,7 @@ primary(X) ::= primary(A) LBRACKET expr(B) RBRACKET. [DOT] // Array access { NEW_AST_NODE(ExprBinary, expr, B); expr->Operation = PEX_ArrayAccess; + expr->Type = NULL; expr->Left = A; expr->Right = B; X = expr; @@ -782,6 +788,7 @@ primary(X) ::= primary(A) DOT IDENTIFIER(B). // Member access { NEW_AST_NODE(ExprMemberAccess, expr, B); expr->Operation = PEX_MemberAccess; + expr->Type = NULL; expr->Left = A; expr->Right = ENamedName(B.Int); X = expr; @@ -1002,6 +1009,7 @@ expr(X) ::= expr(A) QUESTION expr(B) COLON expr(C). { NEW_AST_NODE(ExprTrinary, expr, A); expr->Operation = PEX_Trinary; + expr->Type = NULL; expr->Test = A; expr->Left = B; expr->Right = C; @@ -1089,6 +1097,7 @@ string_constant(X) ::= STRCONST(A). { NEW_AST_NODE(ExprString, strconst, A); strconst->Operation = PEX_StringConst; + strconst->Type = TypeString; strconst->Value = A.String; X = strconst; } @@ -1096,6 +1105,7 @@ string_constant(X) ::= string_constant(A) STRCONST(B). { NEW_AST_NODE(ExprString, strconst, A); strconst->Operation = PEX_StringConst; + strconst->Type = TypeString; strconst->Value = stat->Strings.Alloc(*(A->Value) + *(B.String)); X = strconst; } @@ -1108,6 +1118,7 @@ constant(X) ::= INTCONST(A). { NEW_AST_NODE(ExprInt, intconst, A); intconst->Operation = PEX_IntConst; + intconst->Type = TypeSInt32; intconst->Value = A.Int; X = intconst; } @@ -1115,6 +1126,7 @@ constant(X) ::= FLOATCONST(A). { NEW_AST_NODE(ExprFloat, floatconst, A); floatconst->Operation = PEX_FloatConst; + floatconst->Type = TypeFloat64; floatconst->Value = A.Float; X = floatconst; } diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index 9ee33ab08..7bd12ede1 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -296,6 +296,7 @@ struct ZCC_StateLoop : ZCC_StatePart struct ZCC_Expression : ZCC_TreeNode { EZCCExprType Operation; + PType *Type; }; struct ZCC_StateGoto : ZCC_StatePart From 61666e15153e5e5f1640bf8455033a353ece87e9 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 10 Sep 2013 21:10:48 -0500 Subject: [PATCH 155/232] Consolidate constant expression nodes into a single type - Instead of having ZCC_ExprString, ZCC_ExprInt, and ZCC_ExprFloat, just use a single ZCC_ExprConstant. It should simplify type promotion and constant folding in the future. --- src/zscript/ast.cpp | 48 ++++++++++++++----------------------- src/zscript/zcc-parse.lemon | 28 +++++++++++----------- src/zscript/zcc_parser.h | 28 +++++++--------------- 3 files changed, 41 insertions(+), 63 deletions(-) diff --git a/src/zscript/ast.cpp b/src/zscript/ast.cpp index ae687eefc..dc9422cf4 100644 --- a/src/zscript/ast.cpp +++ b/src/zscript/ast.cpp @@ -442,10 +442,7 @@ static void OpenExprType(FLispString &out, EZCCExprType type) "id", "super", "self", - "string-const", - "int-const", - "uint-const", - "float-const", + "const", "func-call", "array-access", "member-access", @@ -518,30 +515,23 @@ static void PrintExprID(FLispString &out, ZCC_TreeNode *node) out.Close(); } -static void PrintExprString(FLispString &out, ZCC_TreeNode *node) +static void PrintExprConstant(FLispString &out, ZCC_TreeNode *node) { - ZCC_ExprString *enode = (ZCC_ExprString *)node; - assert(enode->Operation == PEX_StringConst); - out.Open("expr-string-const"); - PrintStringConst(out, *enode->Value); - out.Close(); -} - -static void PrintExprInt(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_ExprInt *enode = (ZCC_ExprInt *)node; - assert(enode->Operation == PEX_IntConst || enode->Operation == PEX_UIntConst); - OpenExprType(out, enode->Operation); - out.AddInt(enode->Value); - out.Close(); -} - -static void PrintExprFloat(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_ExprFloat *enode = (ZCC_ExprFloat *)node; - assert(enode->Operation == PEX_FloatConst); - out.Open("expr-float-const"); - out.AddFloat(enode->Value); + ZCC_ExprConstant *enode = (ZCC_ExprConstant *)node; + assert(enode->Operation == PEX_ConstValue); + out.Open("expr-const"); + if (enode->Type == TypeString) + { + PrintStringConst(out, *enode->StringVal); + } + else if (enode->Type == TypeFloat64) + { + out.AddFloat(enode->DoubleVal); + } + else + { + out.AddInt(enode->IntVal); + } out.Close(); } @@ -817,9 +807,7 @@ void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode * PrintClassType, PrintExpression, PrintExprID, - PrintExprString, - PrintExprInt, - PrintExprFloat, + PrintExprConstant, PrintExprFuncCall, PrintExprMemberAccess, PrintExprUnary, diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index 3384bab03..da940dc6f 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -726,7 +726,7 @@ const_def(X) ::= CONST(T) IDENTIFIER(A) EQ expr(B) SEMICOLON. %type expr{ZCC_Expression *} %type primary{ZCC_Expression *} %type unary_expr{ZCC_Expression *} -%type constant{ZCC_Expression *} +%type constant{ZCC_ExprConstant *} %include { #define UNARY_EXPR(X,T) NEW_AST_NODE(ExprUnary, expr, X); expr->Operation = T; expr->Operand = X; expr->Type = NULL @@ -1091,22 +1091,22 @@ named_expr(X) ::= expr(B). /************ Constants ************/ /* Allow C-like concatenation of adjacent string constants. */ -%type string_constant{ZCC_ExprString *} +%type string_constant{ZCC_ExprConstant *} string_constant(X) ::= STRCONST(A). { - NEW_AST_NODE(ExprString, strconst, A); - strconst->Operation = PEX_StringConst; + NEW_AST_NODE(ExprConstant, strconst, A); + strconst->Operation = PEX_ConstValue; strconst->Type = TypeString; - strconst->Value = A.String; + strconst->StringVal = A.String; X = strconst; } string_constant(X) ::= string_constant(A) STRCONST(B). { - NEW_AST_NODE(ExprString, strconst, A); - strconst->Operation = PEX_StringConst; + NEW_AST_NODE(ExprConstant, strconst, A); + strconst->Operation = PEX_ConstValue; strconst->Type = TypeString; - strconst->Value = stat->Strings.Alloc(*(A->Value) + *(B.String)); + strconst->StringVal = stat->Strings.Alloc(*(A->StringVal) + *(B.String)); X = strconst; } @@ -1116,18 +1116,18 @@ constant(X) ::= string_constant(A). } constant(X) ::= INTCONST(A). { - NEW_AST_NODE(ExprInt, intconst, A); - intconst->Operation = PEX_IntConst; + NEW_AST_NODE(ExprConstant, intconst, A); + intconst->Operation = PEX_ConstValue; intconst->Type = TypeSInt32; - intconst->Value = A.Int; + intconst->IntVal = A.Int; X = intconst; } constant(X) ::= FLOATCONST(A). { - NEW_AST_NODE(ExprFloat, floatconst, A); - floatconst->Operation = PEX_FloatConst; + NEW_AST_NODE(ExprConstant, floatconst, A); + floatconst->Operation = PEX_ConstValue; floatconst->Type = TypeFloat64; - floatconst->Value = A.Float; + floatconst->DoubleVal = A.Float; X = floatconst; } diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index 7bd12ede1..3ad675abe 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -75,9 +75,7 @@ enum EZCCTreeNodeType AST_ClassType, AST_Expression, AST_ExprID, - AST_ExprString, - AST_ExprInt, - AST_ExprFloat, + AST_ExprConstant, AST_ExprFuncCall, AST_ExprMemberAccess, AST_ExprUnary, @@ -136,10 +134,7 @@ enum EZCCExprType PEX_ID, PEX_Super, PEX_Self, - PEX_StringConst, - PEX_IntConst, - PEX_UIntConst, - PEX_FloatConst, + PEX_ConstValue, PEX_FuncCall, PEX_ArrayAccess, PEX_MemberAccess, @@ -352,19 +347,14 @@ struct ZCC_ExprID : ZCC_Expression ENamedName Identifier; }; -struct ZCC_ExprString : ZCC_Expression +struct ZCC_ExprConstant : ZCC_Expression { - FString *Value; -}; - -struct ZCC_ExprInt : ZCC_Expression -{ - int Value; -}; - -struct ZCC_ExprFloat : ZCC_Expression -{ - double Value; + union + { + FString *StringVal; + int IntVal; + double DoubleVal; + }; }; struct ZCC_FuncParm : ZCC_TreeNode From 3044fdd0a9d104145991689b229cf4492f453e08 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 10 Sep 2013 21:24:32 -0500 Subject: [PATCH 156/232] Use %f instead of %g in AST dumps - To ensure that floating point constants are identifiable as floating point, FLispString::AddFloat() now prints them with %f. --- src/zscript/ast.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zscript/ast.cpp b/src/zscript/ast.cpp index dc9422cf4..bdb1d429c 100644 --- a/src/zscript/ast.cpp +++ b/src/zscript/ast.cpp @@ -155,7 +155,7 @@ public: void AddFloat(double f) { char buf[32]; - size_t len = mysnprintf(buf, countof(buf), "%g", f); + size_t len = mysnprintf(buf, countof(buf), "%.4f", f); Add(buf, len); } private: From 6545c48e07d2390c8df4126d5ca547dae6809864 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 10 Sep 2013 21:25:50 -0500 Subject: [PATCH 157/232] Accept constant definitions at global scope --- src/zscript/zcc-parse.lemon | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index da940dc6f..b180381c4 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -104,6 +104,7 @@ translation_unit(X) ::= error. { X = NULL; } external_declaration(X) ::= class_definition(A). { X = A; } external_declaration(X) ::= struct_def(A). { X = A; } external_declaration(X) ::= enum_def(A). { X = A; } +external_declaration(X) ::= const_def(A). { X = A; } /* Optional bits. */ opt_semicolon ::= . From aec6aff7a82cb78f98f0c531dfe45b99161f5679 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 10 Sep 2013 21:30:33 -0500 Subject: [PATCH 158/232] Don't accept l as a suffix for floating point numbers in the scanner - We're never going to support long doubles, so don't pretend. --- src/sc_man_scanner.re | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sc_man_scanner.re b/src/sc_man_scanner.re index 02ba61125..328e7afdb 100644 --- a/src/sc_man_scanner.re +++ b/src/sc_man_scanner.re @@ -36,7 +36,7 @@ std2: L = [a-zA-Z_]; H = [a-fA-F0-9]; E = [Ee] [+-]? D+; - FS = [fFlL]; + FS = [fF]; IS = [uUlL]; ESC = [\\] ([abcfnrtv?'"\\] | "x" H+ | O+); From 33344201fafa1f97757fd3a9eac75546be7b44a7 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 10 Sep 2013 21:40:05 -0500 Subject: [PATCH 159/232] Let the scanner returned unsigned integers - The scanner already recognized the u suffix for unsigned integers, but otherwise ignored it. Return it as a proper token. --- src/sc_man.cpp | 15 +++++++++++++-- src/sc_man_scanner.re | 2 +- src/sc_man_tokens.h | 1 + 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/sc_man.cpp b/src/sc_man.cpp index de668ee42..05abe1784 100644 --- a/src/sc_man.cpp +++ b/src/sc_man.cpp @@ -530,8 +530,19 @@ bool FScanner::GetToken () else if (TokenType == TK_IntConst) { char *stopper; - Number = strtol(String, &stopper, 0); - Float = Number; + // Check for unsigned + if (String[StringLen - 1] == 'u' || String[StringLen - 1] == 'U' || + String[StringLen - 2] == 'u' || String[StringLen - 2] == 'U') + { + TokenType = TK_UIntConst; + Number = strtoul(String, &stopper, 0); + Float = (unsigned)Number; + } + else + { + Number = strtol(String, &stopper, 0); + Float = Number; + } } else if (TokenType == TK_FloatConst) { diff --git a/src/sc_man_scanner.re b/src/sc_man_scanner.re index 328e7afdb..4da98736e 100644 --- a/src/sc_man_scanner.re +++ b/src/sc_man_scanner.re @@ -188,7 +188,7 @@ std2: L (L|D)* { RET(TK_Identifier); } - ("0" [xX] H+ IS?) | ("0" D+ IS?) | (D+ IS?) + ("0" [xX] H+ IS?IS?) | ("0" D+ IS?IS?) | (D+ IS?IS?) { RET(TK_IntConst); } (D+ E FS?) | (D* "." D+ E? FS?) | (D+ "." D* E? FS?) diff --git a/src/sc_man_tokens.h b/src/sc_man_tokens.h index e98c457b5..6bc01c184 100644 --- a/src/sc_man_tokens.h +++ b/src/sc_man_tokens.h @@ -2,6 +2,7 @@ xx(TK_Identifier, "identifier") xx(TK_StringConst, "string constant") xx(TK_NameConst, "name constant") xx(TK_IntConst, "integer constant") +xx(TK_UIntConst, "unsigned constant") xx(TK_FloatConst, "float constant") xx(TK_NonWhitespace, "non-whitespace") xx(TK_ColonColon, "'::'") From 1b4851224e717a7841ecfc7bc87360181f697656 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 10 Sep 2013 21:44:32 -0500 Subject: [PATCH 160/232] Let the grammar accept unsigned integer constants --- src/zscript/zcc-parse.lemon | 12 +++++++++++- src/zscript/zcc_parser.cpp | 6 ++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index b180381c4..cbdea0f4f 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -449,7 +449,7 @@ type_name(X) ::= DOT dottable_id(A). * straight away.) */ vector_size(X) ::= . { X.Int = ZCC_Vector3; X.SourceLoc = stat->sc.GetMessageLine(); } -vector_size(X) ::= LT INTCONST(A) GT. +vector_size(X) ::= LT intconst(A) GT. { if (A.Int >= 2 && A.Int <= 4) { @@ -462,6 +462,8 @@ vector_size(X) ::= LT INTCONST(A) GT. } X.SourceLoc = A.SourceLoc; } +intconst(X) ::= INTCONST(A). { X = A; } +intconst(X) ::= UINTCONST(A). { X = A; } /* Type names can also be used as identifiers in contexts where type names * are not normally allowed. */ @@ -1123,6 +1125,14 @@ constant(X) ::= INTCONST(A). intconst->IntVal = A.Int; X = intconst; } +constant(X) ::= UINTCONST(A). +{ + NEW_AST_NODE(ExprConstant, intconst, A); + intconst->Operation = PEX_ConstValue; + intconst->Type = TypeUInt32; + intconst->IntVal = A.Int; + X = intconst; +} constant(X) ::= FLOATCONST(A). { NEW_AST_NODE(ExprConstant, floatconst, A); diff --git a/src/zscript/zcc_parser.cpp b/src/zscript/zcc_parser.cpp index 73301e6b5..a178cb980 100644 --- a/src/zscript/zcc_parser.cpp +++ b/src/zscript/zcc_parser.cpp @@ -140,6 +140,7 @@ static void InitTokenMap() TOKENDEF (TK_Identifier, ZCC_IDENTIFIER); TOKENDEF (TK_StringConst, ZCC_STRCONST); TOKENDEF (TK_IntConst, ZCC_INTCONST); + TOKENDEF (TK_UIntConst, ZCC_UINTCONST); TOKENDEF (TK_FloatConst, ZCC_FLOATCONST); TOKENDEF (TK_NonWhitespace, ZCC_NWS); } @@ -197,6 +198,11 @@ static void DoParse(const char *filename) value.Int = sc.Number; tokentype = ZCC_INTCONST; } + else if (sc.TokenType == TK_UIntConst) + { + value.Int = sc.Number; + tokentype = ZCC_UINTCONST; + } else if (sc.TokenType == TK_FloatConst) { value.Float = sc.Float; From 52d5e74e7e3975a97f539638a30dbc508365339c Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 10 Sep 2013 21:48:15 -0500 Subject: [PATCH 161/232] Mark unsigned constants in AST dumps. - Add the u suffix to unsigned integer constants printed in AST dumps. --- src/zscript/ast.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/zscript/ast.cpp b/src/zscript/ast.cpp index bdb1d429c..b316208e9 100644 --- a/src/zscript/ast.cpp +++ b/src/zscript/ast.cpp @@ -140,10 +140,18 @@ public: { Add(&c, 1); } - void AddInt(int i) + void AddInt(int i, bool un=false) { char buf[16]; - size_t len = mysnprintf(buf, countof(buf), "%d", i); + size_t len; + if (!un) + { + len = mysnprintf(buf, countof(buf), "%d", i); + } + else + { + len = mysnprintf(buf, countof(buf), "%uu", i); + } Add(buf, len); } void AddHex(unsigned x) @@ -528,9 +536,9 @@ static void PrintExprConstant(FLispString &out, ZCC_TreeNode *node) { out.AddFloat(enode->DoubleVal); } - else + else if (enode->Type->IsKindOf(RUNTIME_CLASS(PInt))) { - out.AddInt(enode->IntVal); + out.AddInt(enode->IntVal, static_cast<PInt *>(enode->Type)->Unsigned); } out.Close(); } From b6e525d9359fae00fe524f4dd6eea479835c5ab3 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 10 Sep 2013 21:50:27 -0500 Subject: [PATCH 162/232] Add missing closing " for string constants in AST dumps --- src/zscript/ast.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zscript/ast.cpp b/src/zscript/ast.cpp index b316208e9..1cd25e561 100644 --- a/src/zscript/ast.cpp +++ b/src/zscript/ast.cpp @@ -267,6 +267,7 @@ static void PrintStringConst(FLispString &out, FString str) outstr.AppendFormat("\\x%02X", str[i]); } } + outstr << '"'; out.Add(outstr); } From 33e835b58d428be3ef15987f4cc1a938e83fdabe Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 10 Sep 2013 21:56:13 -0500 Subject: [PATCH 163/232] Accept name constants in the grammar --- src/zscript/ast.cpp | 4 ++++ src/zscript/zcc-parse.lemon | 8 ++++++++ src/zscript/zcc_parser.cpp | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/src/zscript/ast.cpp b/src/zscript/ast.cpp index 1cd25e561..497ac7479 100644 --- a/src/zscript/ast.cpp +++ b/src/zscript/ast.cpp @@ -537,6 +537,10 @@ static void PrintExprConstant(FLispString &out, ZCC_TreeNode *node) { out.AddFloat(enode->DoubleVal); } + else if (enode->Type == TypeName) + { + out.AddName(ENamedName(enode->IntVal)); + } else if (enode->Type->IsKindOf(RUNTIME_CLASS(PInt))) { out.AddInt(enode->IntVal, static_cast<PInt *>(enode->Type)->Unsigned); diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index cbdea0f4f..2e192cf36 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -1141,6 +1141,14 @@ constant(X) ::= FLOATCONST(A). floatconst->DoubleVal = A.Float; X = floatconst; } +constant(X) ::= NAMECONST(A). +{ + NEW_AST_NODE(ExprConstant, floatconst, A); + floatconst->Operation = PEX_ConstValue; + floatconst->Type = TypeName; + floatconst->IntVal = A.Int; + X = floatconst; +} /************ Statements ************/ diff --git a/src/zscript/zcc_parser.cpp b/src/zscript/zcc_parser.cpp index a178cb980..766f28c2a 100644 --- a/src/zscript/zcc_parser.cpp +++ b/src/zscript/zcc_parser.cpp @@ -139,6 +139,7 @@ static void InitTokenMap() TOKENDEF (TK_Identifier, ZCC_IDENTIFIER); TOKENDEF (TK_StringConst, ZCC_STRCONST); + TOKENDEF (TK_NameConst, ZCC_NAMECONST); TOKENDEF (TK_IntConst, ZCC_INTCONST); TOKENDEF (TK_UIntConst, ZCC_UINTCONST); TOKENDEF (TK_FloatConst, ZCC_FLOATCONST); @@ -193,6 +194,11 @@ static void DoParse(const char *filename) value.String = state.Strings.Alloc(sc.String, sc.StringLen); tokentype = ZCC_STRCONST; } + else if (sc.TokenType == TK_NameConst) + { + value.Int = sc.Name; + tokentype = ZCC_NAMECONST; + } else if (sc.TokenType == TK_IntConst) { value.Int = sc.Number; From 2ab39747522a43f97af942de6049747f272c1d64 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 10 Sep 2013 22:01:00 -0500 Subject: [PATCH 164/232] Add a PSymbolConstString class - Constants can be strings, but the existing PSymbolConst couldn't handle them. The old PSymbolConst is now PSymbolConstNumeric, and the new PSymbolConst is a now a baseclass for it and PSymbolConstString. --- src/dobjtype.cpp | 2 + src/dobjtype.h | 57 +++++++++++++++++++--------- src/thingdef/thingdef_expression.cpp | 2 +- src/thingdef/thingdef_parse.cpp | 9 ++--- 4 files changed, 47 insertions(+), 23 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index f10a07ad1..252b22fd3 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2287,6 +2287,8 @@ CCMD(typetable) IMPLEMENT_ABSTRACT_CLASS(PSymbol); IMPLEMENT_CLASS(PSymbolConst); +IMPLEMENT_CLASS(PSymbolConstNumeric); +IMPLEMENT_CLASS(PSymbolConstString); IMPLEMENT_POINTY_CLASS(PSymbolVMFunction) DECLARE_POINTER(Function) END_POINTERS diff --git a/src/dobjtype.h b/src/dobjtype.h index 56ae1b6de..bfc3b966e 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -32,23 +32,6 @@ protected: PSymbol(FName name) { SymbolName = name; } }; -// A constant value --------------------------------------------------------- - -class PSymbolConst : public PSymbol -{ - DECLARE_CLASS(PSymbolConst, PSymbol); -public: - class PType *ValueType; - union - { - int Value; - double Float; - }; - - PSymbolConst(FName name) : PSymbol(name) {} - PSymbolConst() : PSymbol(NAME_None) {} -}; - // An action function ------------------------------------------------------- struct FState; @@ -654,4 +637,44 @@ extern PStatePointer *TypeState; extern PFixed *TypeFixed; extern PAngle *TypeAngle; +// A constant value --------------------------------------------------------- + +class PSymbolConst : public PSymbol +{ + DECLARE_CLASS(PSymbolConst, PSymbol); +public: + PType *ValueType; + + PSymbolConst(FName name, PType *type=NULL) : PSymbol(name), ValueType(type) {} + PSymbolConst() : PSymbol(NAME_None), ValueType(NULL) {} +}; + +// A constant numeric value ------------------------------------------------- + +class PSymbolConstNumeric : public PSymbolConst +{ + DECLARE_CLASS(PSymbolConstNumeric, PSymbolConst); +public: + union + { + int Value; + double Float; + }; + + PSymbolConstNumeric(FName name, PType *type=NULL) : PSymbolConst(name, type) {} + PSymbolConstNumeric() {} +}; + +// A constant string value -------------------------------------------------- + +class PSymbolConstString : public PSymbolConst +{ + DECLARE_CLASS(PSymbolConstString, PSymbolConst); +public: + FString Str; + + PSymbolConstString(FName name, FString &str) : PSymbolConst(name, TypeString), Str(str) {} + PSymbolConstString() {} +}; + #endif diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 1f5d48ab5..f7e598815 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -294,7 +294,7 @@ ExpEmit FxParameter::Emit(VMFunctionBuilder *build) FxExpression *FxConstant::MakeConstant(PSymbol *sym, const FScriptPosition &pos) { FxExpression *x; - PSymbolConst *csym = dyn_cast<PSymbolConst>(sym); + PSymbolConstNumeric *csym = dyn_cast<PSymbolConstNumeric>(sym); if (csym != NULL) { if (csym->ValueType->IsA(RUNTIME_CLASS(PInt))) diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index db8238d1c..2632efcc1 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -202,15 +202,15 @@ static void ParseConstant (FScanner &sc, PSymbolTable *symt, PClassActor *cls) { ExpVal val = static_cast<FxConstant *>(expr)->GetValue(); delete expr; - PSymbolConst *sym = new PSymbolConst(symname); + PSymbolConstNumeric *sym; if (type == TK_Int) { - sym->ValueType = TypeSInt32; + sym = new PSymbolConstNumeric(symname, TypeSInt32); sym->Value = val.GetInt(); } else { - sym->ValueType = TypeFloat64; + sym = new PSymbolConstNumeric(symname, TypeFloat64); sym->Float = val.GetFloat(); } if (symt->AddSymbol (sym) == NULL) @@ -260,8 +260,7 @@ static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClassActor *cls) } delete expr; } - PSymbolConst *sym = new PSymbolConst(symname); - sym->ValueType = TypeSInt32; + PSymbolConstNumeric *sym = new PSymbolConstNumeric(symname, TypeSInt32); sym->Value = currvalue; if (symt->AddSymbol (sym) == NULL) { From d5fa55011856f3cac51336ce70e33e68410fca7a Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Thu, 12 Sep 2013 21:58:06 -0500 Subject: [PATCH 165/232] Make ZCC_TreeNode::AppendSibling() work with lists - Previously, you could only append lone nodes to ZCC_TreeNode lists. Now you can append one list to another. --- src/zscript/zcc_parser.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index 3ad675abe..ba046d723 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -211,17 +211,19 @@ struct ZCC_TreeNode return; } - // The new sibling node should only be in a list with itself. - assert(sibling->SiblingNext == sibling && sibling->SiblingPrev == sibling); - // Check integrity of our sibling list. assert(SiblingPrev->SiblingNext == this); assert(SiblingNext->SiblingPrev == this); + // Check integrity of new sibling list. + assert(sibling->SiblingPrev->SiblingNext = sibling); + assert(sibling->SiblingNext->SiblingPrev = sibling); + + ZCC_TreeNode *siblingend = sibling->SiblingPrev; SiblingPrev->SiblingNext = sibling; sibling->SiblingPrev = SiblingPrev; - SiblingPrev = sibling; - sibling->SiblingNext = this; + SiblingPrev = siblingend; + siblingend->SiblingNext = this; } }; From af8e0f2ba626c8570f2c19b36c1f8835ab21771e Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Thu, 12 Sep 2013 21:39:10 -0500 Subject: [PATCH 166/232] Represent enumerations as constant definitions - Instead of representating enumeration values with a special node type, use the same ZCC_ConstantDef nodes that const_def produces. These are created at the same scope as the ZCC_Enum, rather than being contained entirely within it. To mark the end of enums for a single instance of ZCC_Enum, a ZCC_EnumTerminator node is now appended to the chain of ZCC_ConstantDefs. --- src/zscript/ast.cpp | 11 ++-- src/zscript/zcc-parse.lemon | 117 ++++++++++++++++++++++++++---------- src/zscript/zcc_parser.h | 9 ++- 3 files changed, 93 insertions(+), 44 deletions(-) diff --git a/src/zscript/ast.cpp b/src/zscript/ast.cpp index 497ac7479..ea7862a94 100644 --- a/src/zscript/ast.cpp +++ b/src/zscript/ast.cpp @@ -301,16 +301,13 @@ static void PrintEnum(FLispString &out, ZCC_TreeNode *node) out.Open("enum"); out.AddName(enode->EnumName); PrintBuiltInType(out, enode->EnumType); - PrintNodes(out, enode->Elements, false, true); + out.Add(enode->Elements == NULL ? "nil" : "...", 3); out.Close(); } -static void PrintEnumNode(FLispString &out, ZCC_TreeNode *node) +static void PrintEnumTerminator(FLispString &out, ZCC_TreeNode *node) { - ZCC_EnumNode *enode = (ZCC_EnumNode *)node; - out.Open("enum-node"); - out.AddName(enode->ElemName); - PrintNodes(out, enode->ElemValue, false); + out.Open("enum-term"); out.Close(); } @@ -802,7 +799,7 @@ void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode * PrintClass, PrintStruct, PrintEnum, - PrintEnumNode, + PrintEnumTerminator, PrintStates, PrintStatePart, PrintStateLabel, diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index 2e192cf36..6c86a03a2 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -33,6 +33,16 @@ static void SetNodeLine(ZCC_TreeNode *name, int line) // If a is non-null, appends b to a. Otherwise, sets a to b. #define SAFE_APPEND(a,b) \ if (a == NULL) a = b; else a->AppendSibling(b); + +#define UNARY_EXPR(X,T) NEW_AST_NODE(ExprUnary, expr, X); expr->Operation = T; expr->Operand = X; expr->Type = NULL +#define BINARY_EXPR(X,Y,T) NEW_AST_NODE(ExprBinary, expr, X); expr->Operation = T; expr->Type = NULL; expr->Left = X; expr->Right = Y + +#define NEW_INTCONST_NODE(name,type,val,tok) \ + NEW_AST_NODE(ExprConstant, name, tok); \ + name->Operation = PEX_ConstValue; \ + name->Type = type; \ + name->IntVal = val + } %token_prefix ZCC_ @@ -237,20 +247,81 @@ struct_body(X) ::= struct_member(A) struct_body(B). { X = A; A->AppendSibling(B struct_member(X) ::= declarator_no_fun(A). { X = A; } struct_member(X) ::= enum_def(A). { X = A; } +/*----- Constant Definition ------*/ +/* Like UnrealScript, a constant's type is implied by its value's type. */ +const_def(X) ::= CONST(T) IDENTIFIER(A) EQ expr(B) SEMICOLON. +{ + NEW_AST_NODE(ConstantDef,def,T); + def->Name = A.Name(); + def->Value = B; + def->Symbol = NULL; + X = def; +} + /*----- Enum Definition -----*/ /* Enumerators are lists of named integers. */ -%type enum_list {ZCC_EnumNode *} -%type opt_enum_list {ZCC_EnumNode *} -%type enumerator {ZCC_EnumNode *} +%type enum_list {ZCC_ConstantDef *} +%type opt_enum_list {ZCC_ConstantDef *} +%type enumerator {ZCC_ConstantDef *} -enum_def(X) ::= ENUM(T) IDENTIFIER(A) enum_type(B) LBRACE opt_enum_list(C) RBRACE opt_semicolon. +enum_def(X) ::= ENUM(T) IDENTIFIER(A) enum_type(B) LBRACE opt_enum_list(C) RBRACE(U) opt_semicolon. { NEW_AST_NODE(Enum,def,T); def->EnumName = A.Name(); def->EnumType = (EZCCBuiltinType)B.Int; def->Elements = C; + + // If the first element does not have an explicit value, make it 0. + if (C != NULL) + { + ZCC_ConstantDef *node = C, *prev = node; + ZCC_ExprConstant *one = NULL; + + if (node->Value == NULL) + { + NEW_INTCONST_NODE(zero, TypeSInt32, 0, C); + node->Value = zero; + } + for (node = static_cast<ZCC_ConstantDef *>(node->SiblingNext); + node != C; + prev = node, node = static_cast<ZCC_ConstantDef *>(node->SiblingNext)) + { + assert(node->NodeType == AST_ConstantDef); + // Leave explicit values alone. + if (node->Value != NULL) + { + continue; + } + // Compute implicit values by adding one to the preceding value. + assert(prev->Value != NULL); + // If the preceding node is a constant, then we can do this now. + if (prev->Value->Operation == PEX_ConstValue && prev->Value->Type->IsA(RUNTIME_CLASS(PInt))) + { + NEW_INTCONST_NODE(cval, prev->Value->Type, static_cast<ZCC_ExprConstant *>(prev->Value)->IntVal + 1, node); + node->Value = cval; + } + // Otherwise, create a new addition expression to add 1. + else + { + if (one == NULL) + { // Use a single 1 node for the right-hand side of the addition. + NEW_INTCONST_NODE(cval, TypeSInt32, 1, T); + one = cval; + } + BINARY_EXPR(prev->Value, one, PEX_Add); + node->Value = expr; + } + } + // Add a new terminating node, to indicate that the ConstantDefs for this enum are done. + NEW_AST_NODE(EnumTerminator,term,U); + C->AppendSibling(term); + } + if (C != NULL) + { + def->AppendSibling(C); + } X = def; } @@ -266,16 +337,18 @@ opt_enum_list(X) ::= enum_list(A) opt_comma. { X = A; } enumerator(X) ::= IDENTIFIER(A). { - NEW_AST_NODE(EnumNode,node,A); - node->ElemName = A.Name(); - node->ElemValue = NULL; + NEW_AST_NODE(ConstantDef,node,A); + node->Name = A.Name(); + node->Value = NULL; + node->Symbol = NULL; X = node; } enumerator(X) ::= IDENTIFIER(A) EQ expr(B). /* Expression must be constant. */ { - NEW_AST_NODE(EnumNode,node,A); - node->ElemName = A.Name(); - node->ElemValue = B; + NEW_AST_NODE(ConstantDef,node,A); + node->Name = A.Name(); + node->Value = B; + node->Symbol = NULL; X = node; } @@ -711,15 +784,6 @@ func_param_flags(X) ::= func_param_flags(A) IN(T). { X.Int = A.Int | ZCC_In; X func_param_flags(X) ::= func_param_flags(A) OUT(T). { X.Int = A.Int | ZCC_Out; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } func_param_flags(X) ::= func_param_flags(A) OPTIONAL(T). { X.Int = A.Int | ZCC_Optional; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } -/* Like UnrealScript, a constant's type is implied by its value's type. */ -const_def(X) ::= CONST(T) IDENTIFIER(A) EQ expr(B) SEMICOLON. -{ - NEW_AST_NODE(ConstantDef,def,T); - def->Name = A.Name(); - def->Value = B; - X = def; -} - /************ Expressions ************/ /* We use default to access a class's default instance. */ @@ -731,11 +795,6 @@ const_def(X) ::= CONST(T) IDENTIFIER(A) EQ expr(B) SEMICOLON. %type unary_expr{ZCC_Expression *} %type constant{ZCC_ExprConstant *} -%include { -#define UNARY_EXPR(X,T) NEW_AST_NODE(ExprUnary, expr, X); expr->Operation = T; expr->Operand = X; expr->Type = NULL -#define BINARY_EXPR(X,Y,T) NEW_AST_NODE(ExprBinary, expr, X); expr->Operation = T; expr->Type = NULL; expr->Left = X; expr->Right = Y -} - /*----- Primary Expressions -----*/ primary(X) ::= IDENTIFIER(A). @@ -1119,18 +1178,12 @@ constant(X) ::= string_constant(A). } constant(X) ::= INTCONST(A). { - NEW_AST_NODE(ExprConstant, intconst, A); - intconst->Operation = PEX_ConstValue; - intconst->Type = TypeSInt32; - intconst->IntVal = A.Int; + NEW_INTCONST_NODE(intconst, TypeSInt32, A.Int, A); X = intconst; } constant(X) ::= UINTCONST(A). { - NEW_AST_NODE(ExprConstant, intconst, A); - intconst->Operation = PEX_ConstValue; - intconst->Type = TypeUInt32; - intconst->IntVal = A.Int; + NEW_INTCONST_NODE(intconst, TypeUInt32, A.Int, A); X = intconst; } constant(X) ::= FLOATCONST(A). diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index ba046d723..f5131e839 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -57,7 +57,7 @@ enum EZCCTreeNodeType AST_Class, AST_Struct, AST_Enum, - AST_EnumNode, + AST_EnumTerminator, AST_States, AST_StatePart, AST_StateLabel, @@ -251,13 +251,11 @@ struct ZCC_Enum : ZCC_TreeNode { ENamedName EnumName; EZCCBuiltinType EnumType; - struct ZCC_EnumNode *Elements; + struct ZCC_ConstantDef *Elements; }; -struct ZCC_EnumNode : ZCC_TreeNode +struct ZCC_EnumTerminator : ZCC_TreeNode { - ENamedName ElemName; - ZCC_TreeNode *ElemValue; }; struct ZCC_States : ZCC_TreeNode @@ -478,6 +476,7 @@ struct ZCC_ConstantDef : ZCC_TreeNode { ENamedName Name; ZCC_Expression *Value; + PSymbolConst *Symbol; }; struct ZCC_Declarator : ZCC_TreeNode From 2a1414ad6638a21c64737c77a310c52200e5172f Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Thu, 12 Sep 2013 22:06:57 -0500 Subject: [PATCH 167/232] Use labels in autogenerated enum value expressions - For an enum like this: enum { value1 = SOME_NUM*2, value2 }; Generate an increment expression for value2 of the form (add (id value1) 1) and not (add (* SOME_NUM 2) 1) --- src/zscript/zcc-parse.lemon | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index 6c86a03a2..e4f0d1fbd 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -310,7 +310,12 @@ enum_def(X) ::= ENUM(T) IDENTIFIER(A) enum_type(B) LBRACE opt_enum_list(C) RBRAC NEW_INTCONST_NODE(cval, TypeSInt32, 1, T); one = cval; } - BINARY_EXPR(prev->Value, one, PEX_Add); + NEW_AST_NODE(ExprID, label, node); + label->Operation = PEX_ID; + label->Identifier = prev->Name; + label->Type = NULL; + + BINARY_EXPR(label, one, PEX_Add); node->Value = expr; } } From 743b05189e8181bd71088691c4f015ad09ccbeb2 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Thu, 12 Sep 2013 22:22:43 -0500 Subject: [PATCH 168/232] Give the parser knowledge of constants for unary - and + - Since the tokenizer never gives the parser negative numbers but always a unary minus followed by a positive number, it seems reasonable to make the parser smart enough to turn these into negative constants without generating extra tree nodes. - And since we're doing it for unary -, we might as well do it for unary + as well and avoid extra nodes when we know we don't need them. --- src/zscript/zcc-parse.lemon | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index e4f0d1fbd..a8e069511 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -884,15 +884,40 @@ unary_expr(X) ::= primary(A). } unary_expr(X) ::= SUB unary_expr(A). [UNARY] { - UNARY_EXPR(A,PEX_Negate); - X = expr; + ZCC_ExprConstant *con = static_cast<ZCC_ExprConstant *>(A); + if (A->Operation == PEX_ConstValue && (con->Type->IsA(RUNTIME_CLASS(PInt)) || con->Type->IsA(RUNTIME_CLASS(PFloat)))) + { // For constants, manipulate the child node directly, and don't create a new node. + if (con->Type->IsA(RUNTIME_CLASS(PInt))) + { + con->IntVal = -con->IntVal; + } + else + { + con->DoubleVal = -con->DoubleVal; + } + X = A; + } + else + { // For everything else, create a new node and do the negation later. + 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; + // But we can do that right now for constant numerals. + ZCC_ExprConstant *con = static_cast<ZCC_ExprConstant *>(A); + if (A->Operation != PEX_ConstValue || (!con->Type->IsA(RUNTIME_CLASS(PInt)) && !con->Type->IsA(RUNTIME_CLASS(PFloat)))) + { + UNARY_EXPR(A,PEX_AntiNegate); + X = expr; + } + else + { + X = A; + } } unary_expr(X) ::= SUBSUB unary_expr(A). [UNARY] { From 0fb9f98a96f0d5516c5982bef758a34725219e21 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 20 Sep 2013 21:10:20 -0500 Subject: [PATCH 169/232] Add void and error types; rejigger pointer types - Added TypeVoid for statements, which produce no type. - Added TypeError for expressions whose arguments are incompatible. - Pointers now derive from PBasicType instead of PInt. Since they have their own register sets in the VM, this seems to make more sense than treating them as integers. --- src/dobjtype.cpp | 19 ++++++++++++------- src/dobjtype.h | 35 ++++++++++++++++++++++++++--------- 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 252b22fd3..210d2db2b 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -61,6 +61,8 @@ FTypeTable TypeTable; TArray<PClass *> PClass::AllClasses; bool PClass::bShutdown; +PErrorType *TypeError; +PVoidType *TypeVoid; PInt *TypeSInt8, *TypeUInt8; PInt *TypeSInt16, *TypeUInt16; PInt *TypeSInt32, *TypeUInt32; @@ -73,7 +75,6 @@ PStatePointer *TypeState; PFixed *TypeFixed; PAngle *TypeAngle; - // PRIVATE DATA DEFINITIONS ------------------------------------------------ // A harmless non-NULL FlatPointer for classes without pointers. @@ -81,6 +82,9 @@ static const size_t TheEnd = ~(size_t)0; // CODE -------------------------------------------------------------------- +IMPLEMENT_CLASS(PErrorType) +IMPLEMENT_CLASS(PVoidType) + void DumpTypeTable() { int used = 0; @@ -300,6 +304,8 @@ void PType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const void PType::StaticInit() { + RUNTIME_CLASS(PErrorType)->TypeTableType = RUNTIME_CLASS(PErrorType); + RUNTIME_CLASS(PVoidType)->TypeTableType = RUNTIME_CLASS(PVoidType); RUNTIME_CLASS(PInt)->TypeTableType = RUNTIME_CLASS(PInt); RUNTIME_CLASS(PFloat)->TypeTableType = RUNTIME_CLASS(PFloat); RUNTIME_CLASS(PString)->TypeTableType = RUNTIME_CLASS(PString); @@ -320,6 +326,8 @@ void PType::StaticInit() RUNTIME_CLASS(PFixed)->TypeTableType = RUNTIME_CLASS(PFixed); RUNTIME_CLASS(PAngle)->TypeTableType = RUNTIME_CLASS(PAngle); + TypeTable.AddType(TypeError = new PErrorType); + TypeTable.AddType(TypeVoid = new PVoidType); TypeTable.AddType(TypeSInt8 = new PInt(1, false)); TypeTable.AddType(TypeUInt8 = new PInt(1, true)); TypeTable.AddType(TypeSInt16 = new PInt(2, false)); @@ -877,9 +885,8 @@ IMPLEMENT_CLASS(PStatePointer) //========================================================================== PStatePointer::PStatePointer() -: PInt(sizeof(FState *), true) +: PBasicType(sizeof(FState *), __alignof(FState *)) { - Align = __alignof(FState *); } @@ -896,9 +903,8 @@ END_POINTERS //========================================================================== PPointer::PPointer() -: PInt(sizeof(void *), true), PointedType(NULL) +: PBasicType(sizeof(void *), __alignof(void *)), PointedType(NULL) { - Align = __alignof(void *); } //========================================================================== @@ -908,9 +914,8 @@ PPointer::PPointer() //========================================================================== PPointer::PPointer(PType *pointsat) -: PInt(sizeof(void *), true), PointedType(pointsat) +: PBasicType(sizeof(void *), __alignof(void *)), PointedType(pointsat) { - Align = __alignof(void *); } //========================================================================== diff --git a/src/dobjtype.h b/src/dobjtype.h index bfc3b966e..1e9cebf02 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -165,6 +165,22 @@ public: static void StaticInit(); }; +// Not-really-a-type types -------------------------------------------------- + +class PErrorType : public PType +{ + DECLARE_CLASS(PErrorType, PType); +public: + PErrorType() : PType(0, 1) {} +}; + +class PVoidType : public PType +{ + DECLARE_CLASS(PVoidType, PType); +public: + PVoidType() : PType(0, 1) {} +}; + // Some categorization typing ----------------------------------------------- class PBasicType : public PType @@ -290,16 +306,16 @@ public: // Pointers ----------------------------------------------------------------- -class PStatePointer : public PInt +class PStatePointer : public PBasicType { - DECLARE_CLASS(PStatePointer, PInt); + DECLARE_CLASS(PStatePointer, PBasicType); public: PStatePointer(); }; -class PPointer : public PInt +class PPointer : public PBasicType { - DECLARE_CLASS(PPointer, PInt); + DECLARE_CLASS(PPointer, PBasicType); HAS_OBJECT_POINTERS; public: PPointer(PType *pointsat); @@ -316,17 +332,14 @@ protected: PPointer(); }; -class PClass; class PClassPointer : public PPointer { DECLARE_CLASS(PClassPointer, PPointer); HAS_OBJECT_POINTERS; public: - PClassPointer(PClass *restrict); + PClassPointer(class PClass *restrict); - PClass *ClassRestriction; - - typedef PClass *Type2; + class PClass *ClassRestriction; virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; @@ -625,6 +638,8 @@ PPrototype *NewPrototype(const TArray<PType *> &rettypes, const TArray<PType *> // Built-in types ----------------------------------------------------------- +extern PErrorType *TypeError; +extern PVoidType *TypeVoid; extern PInt *TypeSInt8, *TypeUInt8; extern PInt *TypeSInt16, *TypeUInt16; extern PInt *TypeSInt32, *TypeUInt32; @@ -662,6 +677,8 @@ public: }; PSymbolConstNumeric(FName name, PType *type=NULL) : PSymbolConst(name, type) {} + PSymbolConstNumeric(FName name, PType *type, int val) : PSymbolConst(name, type), Value(val) {} + PSymbolConstNumeric(FName name, PType *type, double val) : PSymbolConst(name, type), Float(val) {} PSymbolConstNumeric() {} }; From 19486427580476d3a27df7b050626a5e2161eb78 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 25 Sep 2013 20:46:13 -0500 Subject: [PATCH 170/232] Add Printf extension %H - This conversion has behavior similar to %g: It automatically behaves like %f or %e based on the number of output characters. However, unlike %g, this decision is also based on what will produce the smallest string without truncating the output. The precision field (the * in %.*f) is ignored. Converting a double to text with %H and then back to a double should be lossless. --- src/zstrformat.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/zstrformat.cpp b/src/zstrformat.cpp index c048595ab..7433dd574 100644 --- a/src/zstrformat.cpp +++ b/src/zstrformat.cpp @@ -638,6 +638,12 @@ namespace StringFormat } goto fp_begin; } + else if (type == 'H') + { // %H is an extension that behaves similarly to %g, except it automatically + // selects precision based on whatever will produce the smallest string. + expchar = 'e'; + goto fp_begin; + } #if 0 // The hdtoa function provided with FreeBSD uses a hexadecimal FP constant. // Microsoft's compiler does not support these, so I would need to hack it @@ -690,7 +696,7 @@ fp_begin: precision = DEFPREC; } dblarg = va_arg(arglist, double); - obuff = dtoaresult = dtoa(dblarg, expchar ? 2 : 3, precision, &expt, &signflag, &dtoaend); + obuff = dtoaresult = dtoa(dblarg, type != 'H' ? (expchar ? 2 : 3) : 0, precision, &expt, &signflag, &dtoaend); //fp_common: decimal_point = localeconv()->decimal_point; flags |= F_SIGNED; @@ -742,6 +748,22 @@ fp_begin: } } } + else if (type == 'H') + { + if (expt > -(ndig + 2) && expt <= (ndig + 4)) + { // Make %H smell like %f + expchar = '\0'; + precision = ndig - expt; + if (precision < 0) + { + precision = 0; + } + } + else + {// Make %H smell like %e + precision = ndig; + } + } if (expchar) { expsize = exponent(expstr, expt - 1, expchar); From a0dbcb5d5bcdbedfccba25137952208236ee0f86 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sat, 28 Sep 2013 21:08:30 -0500 Subject: [PATCH 171/232] Add TRUE and FALSE terminals to the zcc grammar - I can't believe I completely forgot to let the parser handle true and false literals. - Consolidate all the %include blocks in zcc-parse.lemon into a single one, because Lemon all of a sudden decided it didn't like me having more than one in the grammar file. - Added a PBool type to represent boolean values with. --- src/dobjtype.cpp | 7 +++++ src/dobjtype.h | 8 ++++++ src/zscript/zcc-parse.lemon | 53 ++++++++++++++++++++----------------- 3 files changed, 44 insertions(+), 24 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 210d2db2b..ecc0b5048 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -66,6 +66,7 @@ PVoidType *TypeVoid; PInt *TypeSInt8, *TypeUInt8; PInt *TypeSInt16, *TypeUInt16; PInt *TypeSInt32, *TypeUInt32; +PBool *TypeBool; PFloat *TypeFloat32, *TypeFloat64; PString *TypeString; PName *TypeName; @@ -307,6 +308,7 @@ void PType::StaticInit() RUNTIME_CLASS(PErrorType)->TypeTableType = RUNTIME_CLASS(PErrorType); RUNTIME_CLASS(PVoidType)->TypeTableType = RUNTIME_CLASS(PVoidType); RUNTIME_CLASS(PInt)->TypeTableType = RUNTIME_CLASS(PInt); + RUNTIME_CLASS(PBool)->TypeTableType = RUNTIME_CLASS(PBool); RUNTIME_CLASS(PFloat)->TypeTableType = RUNTIME_CLASS(PFloat); RUNTIME_CLASS(PString)->TypeTableType = RUNTIME_CLASS(PString); RUNTIME_CLASS(PName)->TypeTableType = RUNTIME_CLASS(PName); @@ -334,6 +336,7 @@ void PType::StaticInit() TypeTable.AddType(TypeUInt16 = new PInt(2, true)); TypeTable.AddType(TypeSInt32 = new PInt(4, false)); TypeTable.AddType(TypeUInt32 = new PInt(4, true)); + TypeTable.AddType(TypeBool = new PBool); TypeTable.AddType(TypeFloat32 = new PFloat(4)); TypeTable.AddType(TypeFloat64 = new PFloat(8)); TypeTable.AddType(TypeString = new PString); @@ -561,6 +564,10 @@ int PInt::GetRegType() const return REGT_INT; } +/* PBool ******************************************************************/ + +IMPLEMENT_CLASS(PBool) + /* PFloat *****************************************************************/ IMPLEMENT_CLASS(PFloat) diff --git a/src/dobjtype.h b/src/dobjtype.h index 1e9cebf02..2861b1da2 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -230,6 +230,13 @@ protected: PInt(); }; +class PBool : public PInt +{ + DECLARE_CLASS(PBool, PInt); +public: + PBool() : PInt(sizeof(bool), true) {} +}; + class PFloat : public PBasicType { DECLARE_CLASS(PFloat, PBasicType); @@ -643,6 +650,7 @@ extern PVoidType *TypeVoid; extern PInt *TypeSInt8, *TypeUInt8; extern PInt *TypeSInt16, *TypeUInt16; extern PInt *TypeSInt32, *TypeUInt32; +extern PBool *TypeBool; extern PFloat *TypeFloat32, *TypeFloat64; extern PString *TypeString; extern PName *TypeName; diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index a8e069511..44bf56fb3 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -43,6 +43,25 @@ static void SetNodeLine(ZCC_TreeNode *name, int line) name->Type = type; \ name->IntVal = val + struct ClassFlagsBlock { + VM_UWORD Flags; + ZCC_Identifier *Replaces; + }; + + struct StateOpts { + ZCC_Expression *Offset; + bool Bright; + }; + + struct VarOrFun + { + ZCC_VarName *VarNames; + ZCC_FuncParamDecl *FuncParams; + ZCC_CompoundStmt *FuncBody; + ENamedName FuncName; + int FuncFlags; + int SourceLoc; + }; } %token_prefix ZCC_ @@ -164,12 +183,6 @@ class_ancestry(X) ::= . { X = NULL; } class_ancestry(X) ::= COLON dottable_id(A). { X = A; } %type class_flags{ClassFlagsBlock} -%include { - struct ClassFlagsBlock { - VM_UWORD Flags; - ZCC_Identifier *Replaces; - }; -} class_flags(X) ::= . { X.Flags = 0; X.Replaces = NULL; } class_flags(X) ::= class_flags(A) ABSTRACT. { X.Flags = A.Flags | 0/*FIXME*/; X.Replaces = A.Replaces; } class_flags(X) ::= class_flags(A) NATIVE. { X.Flags = A.Flags | 0/*FIXME*/; X.Replaces = A.Replaces; } @@ -369,12 +382,6 @@ enumerator(X) ::= IDENTIFIER(A) EQ expr(B). /* Expression must be constant. */ %type state_call {ZCC_ExprFuncCall *} %type state_call_params {ZCC_FuncParm *} -%include { - struct StateOpts { - ZCC_Expression *Offset; - bool Bright; - }; -} %type state_opts {StateOpts} states_def(X) ::= STATES(T) scanner_mode LBRACE states_body(A) RBRACE. @@ -618,18 +625,6 @@ array_size(X) ::= array_size(A) array_size_expr(B). X = A; } -%include -{ - struct VarOrFun - { - ZCC_VarName *VarNames; - ZCC_FuncParamDecl *FuncParams; - ZCC_CompoundStmt *FuncBody; - ENamedName FuncName; - int FuncFlags; - int SourceLoc; - }; -} %type variables_or_function {VarOrFun} /* Multiple type names are only valid for functions. */ @@ -1232,6 +1227,16 @@ constant(X) ::= NAMECONST(A). floatconst->IntVal = A.Int; X = floatconst; } +constant(X) ::= FALSE(A). +{ + NEW_INTCONST_NODE(boolconst, TypeBool, false, A); + X = boolconst; +} +constant(X) ::= TRUE(A). +{ + NEW_INTCONST_NODE(boolconst, TypeBool, true, A); + X = boolconst; +} /************ Statements ************/ From 4bd5bf310b68ad549b85ee11180ae6dcf0b95bfd Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 2 Oct 2013 23:28:06 -0500 Subject: [PATCH 172/232] Do not use GT, GTEQ, or NEQ operators in the AST. - Since the VM doesn't directly support the GT, GTEQ, and NEQ comparisons, don't use them in the trees either. Instead, wrap them as LTEQ, LT, and EQEQ inside a BoolNot operator. --- src/zscript/zcc-parse.lemon | 93 +++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 45 deletions(-) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index 44bf56fb3..a3c9d1141 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -34,8 +34,8 @@ static void SetNodeLine(ZCC_TreeNode *name, int line) #define SAFE_APPEND(a,b) \ if (a == NULL) a = b; else a->AppendSibling(b); -#define UNARY_EXPR(X,T) NEW_AST_NODE(ExprUnary, expr, X); expr->Operation = T; expr->Operand = X; expr->Type = NULL -#define BINARY_EXPR(X,Y,T) NEW_AST_NODE(ExprBinary, expr, X); expr->Operation = T; expr->Type = NULL; expr->Left = X; expr->Right = Y +#define UNARY_EXPR(X,T) NEW_AST_NODE(ExprUnary, expr1, X); expr1->Operation = T; expr1->Operand = X; expr1->Type = NULL +#define BINARY_EXPR(X,Y,T) NEW_AST_NODE(ExprBinary, expr2, X); expr2->Operation = T; expr2->Type = NULL; expr2->Left = X; expr2->Right = Y #define NEW_INTCONST_NODE(name,type,val,tok) \ NEW_AST_NODE(ExprConstant, name, tok); \ @@ -329,7 +329,7 @@ enum_def(X) ::= ENUM(T) IDENTIFIER(A) enum_type(B) LBRACE opt_enum_list(C) RBRAC label->Type = NULL; BINARY_EXPR(label, one, PEX_Add); - node->Value = expr; + node->Value = expr2; } } // Add a new terminating node, to indicate that the ConstantDefs for this enum are done. @@ -858,17 +858,17 @@ primary(X) ::= primary(A) DOT IDENTIFIER(B). // Member access primary(X) ::= primary(A) ADDADD. /* postfix++ */ { UNARY_EXPR(A,PEX_PostInc); - X = expr; + X = expr1; } primary(X) ::= primary(A) SUBSUB. /* postfix-- */ { UNARY_EXPR(A,PEX_PostDec); - X = expr; + X = expr1; } primary(X) ::= SCOPE primary(B). { BINARY_EXPR(NULL,B,PEX_Scope); - X = expr; + X = expr2; } /*----- Unary Expressions -----*/ @@ -895,7 +895,7 @@ unary_expr(X) ::= SUB unary_expr(A). [UNARY] else { // For everything else, create a new node and do the negation later. UNARY_EXPR(A,PEX_Negate); - X = expr; + X = expr1; } } unary_expr(X) ::= ADD unary_expr(A). [UNARY] @@ -907,7 +907,7 @@ unary_expr(X) ::= ADD unary_expr(A). [UNARY] if (A->Operation != PEX_ConstValue || (!con->Type->IsA(RUNTIME_CLASS(PInt)) && !con->Type->IsA(RUNTIME_CLASS(PFloat)))) { UNARY_EXPR(A,PEX_AntiNegate); - X = expr; + X = expr1; } else { @@ -917,32 +917,32 @@ unary_expr(X) ::= ADD unary_expr(A). [UNARY] unary_expr(X) ::= SUBSUB unary_expr(A). [UNARY] { UNARY_EXPR(A,PEX_PreDec); - X = expr; + X = expr1; } unary_expr(X) ::= ADDADD unary_expr(A). [UNARY] { UNARY_EXPR(A,PEX_PreInc); - X = expr; + X = expr1; } unary_expr(X) ::= TILDE unary_expr(A). [UNARY] { UNARY_EXPR(A,PEX_BitNot); - X = expr; + X = expr1; } unary_expr(X) ::= BANG unary_expr(A). [UNARY] { UNARY_EXPR(A,PEX_BoolNot); - X = expr; + X = expr1; } unary_expr(X) ::= SIZEOF unary_expr(A). [UNARY] { UNARY_EXPR(A,PEX_SizeOf); - X = expr; + X = expr1; } unary_expr(X) ::= ALIGNOF unary_expr(A). [UNARY] { UNARY_EXPR(A,PEX_AlignOf); - X = expr; + X = expr1; } /* Due to parsing conflicts, C-style casting is not supported. You @@ -958,136 +958,139 @@ expr(X) ::= unary_expr(A). expr(X) ::= expr(A) ADD expr(B). /* a + b */ { BINARY_EXPR(A,B,PEX_Add); - X = expr; + X = expr2; } expr(X) ::= expr(A) SUB expr(B). /* a - b */ { BINARY_EXPR(A,B,PEX_Sub); - X = expr; + X = expr2; } expr(X) ::= expr(A) MUL expr(B). /* a * b */ { BINARY_EXPR(A,B,PEX_Mul); - X = expr; + X = expr2; } expr(X) ::= expr(A) DIV expr(B). /* a / b */ { BINARY_EXPR(A,B,PEX_Div); - X = expr; + X = expr2; } expr(X) ::= expr(A) MOD expr(B). /* a % b */ { BINARY_EXPR(A,B,PEX_Mod); - X = expr; + X = expr2; } expr(X) ::= expr(A) POW expr(B). /* a ** b */ { BINARY_EXPR(A,B,PEX_Pow); - X = expr; + X = expr2; } expr(X) ::= expr(A) CROSSPROD expr(B). /* a cross b */ { BINARY_EXPR(A,B,PEX_CrossProduct); - X = expr; + X = expr2; } expr(X) ::= expr(A) DOTPROD expr(B). /* a dot b */ { BINARY_EXPR(A,B,PEX_DotProduct); - X = expr; + X = expr2; } expr(X) ::= expr(A) LSH expr(B). /* a << b */ { BINARY_EXPR(A,B,PEX_LeftShift); - X = expr; + X = expr2; } expr(X) ::= expr(A) RSH expr(B). /* a >> b */ { BINARY_EXPR(A,B,PEX_RightShift); - X = expr; + X = expr2; } expr(X) ::= expr(A) DOTDOT expr(B). /* a .. b */ { BINARY_EXPR(A,B,PEX_Concat); - X = expr; + X = expr2; } expr(X) ::= expr(A) LT expr(B). /* a < b */ { BINARY_EXPR(A,B,PEX_LT); - X = expr; + X = expr2; } expr(X) ::= expr(A) GT expr(B). /* a > b */ { - BINARY_EXPR(A,B,PEX_GT); - X = expr; + BINARY_EXPR(A,B,PEX_LTEQ); + UNARY_EXPR(expr2,PEX_BoolNot); + X = expr1; } expr(X) ::= expr(A) LTEQ expr(B). /* a <= b */ { BINARY_EXPR(A,B,PEX_LTEQ); - X = expr; + X = expr2; } expr(X) ::= expr(A) GTEQ expr(B). /* a >= b */ { - BINARY_EXPR(A,B,PEX_GTEQ); - X = expr; + BINARY_EXPR(A,B,PEX_LT); + UNARY_EXPR(expr1,PEX_BoolNot); + X = expr1; } expr(X) ::= expr(A) LTGTEQ expr(B). /* a <>= b */ { BINARY_EXPR(A,B,PEX_LTGTEQ); - X = expr; + X = expr2; } expr(X) ::= expr(A) IS expr(B). /* a is b */ { BINARY_EXPR(A,B,PEX_Is); - X = expr; + X = expr2; } expr(X) ::= expr(A) EQEQ expr(B). /* a == b */ { BINARY_EXPR(A,B,PEX_EQEQ); - X = expr; + X = expr2; } expr(X) ::= expr(A) NEQ expr(B). /* a != b */ { - BINARY_EXPR(A,B,PEX_NEQ); - X = expr; + BINARY_EXPR(A,B,PEX_EQEQ); + UNARY_EXPR(expr2,PEX_BoolNot); + X = expr1; } expr(X) ::= expr(A) APPROXEQ expr(B). /* a ~== b */ { BINARY_EXPR(A,B,PEX_APREQ); - X = expr; + X = expr2; } expr(X) ::= expr(A) AND expr(B). /* a & b */ { BINARY_EXPR(A,B,PEX_BitAnd); - X = expr; + X = expr2; } expr(X) ::= expr(A) XOR expr(B). /* a ^ b */ { BINARY_EXPR(A,B,PEX_BitXor); - X = expr; + X = expr2; } expr(X) ::= expr(A) OR expr(B). /* a | b */ { BINARY_EXPR(A,B,PEX_BitOr); - X = expr; + X = expr2; } expr(X) ::= expr(A) ANDAND expr(B). /* a && b */ { BINARY_EXPR(A,B,PEX_BoolAnd); - X = expr; + X = expr2; } expr(X) ::= expr(A) OROR expr(B). /* a || b */ { BINARY_EXPR(A,B,PEX_BoolOr); - X = expr; + X = expr2; } expr(X) ::= expr(A) SCOPE expr(B). { BINARY_EXPR(A,B,PEX_Scope); - X = expr; + X = expr2; } /*----- Trinary Expression -----*/ @@ -1337,7 +1340,7 @@ iteration_statement(X) ::= while_or_until(TY) LPAREN expr(EX) RPAREN statement(S if (TY.Int == ZCC_UNTIL) { // Negate the loop condition UNARY_EXPR(EX,PEX_BoolNot); - iter->LoopCondition = expr; + iter->LoopCondition = expr1; } else { @@ -1355,7 +1358,7 @@ iteration_statement(X) ::= DO(T) statement(ST) while_or_until(TY) LPAREN expr(EX if (TY.Int == ZCC_UNTIL) { // Negate the loop condition UNARY_EXPR(EX,PEX_BoolNot); - iter->LoopCondition = expr; + iter->LoopCondition = expr1; } else { From c7e817dfb9f132d38fe67e0448c752e513b301cf Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Thu, 17 Oct 2013 23:01:04 -0500 Subject: [PATCH 173/232] Added type conversion search routines - PType::FindConversion() can find a path to convert one type to another. This is completely generic and can handle any number of conversion functions. --- src/dobjtype.cpp | 153 +++++++++++++++++++++++++++++++++++++++++++++++ src/dobjtype.h | 62 +++++++++++++++++++ 2 files changed, 215 insertions(+) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index ecc0b5048..aaa507c09 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -213,6 +213,159 @@ PType::~PType() { } +//========================================================================== +// +// PType :: AddConversion +// +//========================================================================== + +bool PType::AddConversion(PType *target, void (*convertconst)(ZCC_ExprConstant *, class FSharedStringArena &)) +{ + // Make sure a conversion hasn't already been registered + for (unsigned i = 0; i < Conversions.Size(); ++i) + { + if (Conversions[i].TargetType == target) + return false; + } + Conversions.Push(Conversion(target, convertconst)); + return true; +} + +//========================================================================== +// +// PType :: FindConversion +// +// Returns <0 if there is no path to target. Otherwise, returns the distance +// to target and fills slots (if non-NULL) with the necessary conversions +// to get there. A result of 0 means this is the target. +// +//========================================================================== + +int PType::FindConversion(PType *target, const PType::Conversion **slots, int numslots) +{ + if (this == target) + { + return 0; + } + // The queue is implemented as a ring buffer + VisitQueue queue; + VisitedNodeSet visited; + + // Use a breadth-first search to find the shortest path to the target. + MarkPred(NULL, -1, -1); + queue.Push(this); + visited.Insert(this); + while (!queue.IsEmpty()) + { + PType *t = queue.Pop(); + if (t == target) + { // found it + if (slots != NULL) + { + if (t->Distance >= numslots) + { // Distance is too far for the output + return -2; + } + t->FillConversionPath(slots); + } + return t->Distance + 1; + } + for (unsigned i = 0; i < t->Conversions.Size(); ++i) + { + PType *succ = t->Conversions[i].TargetType; + if (!visited.Check(succ)) + { + succ->MarkPred(t, i, Distance + 1); + visited.Insert(succ); + queue.Push(succ); + } + } + } + return -1; +} + +//========================================================================== +// +// PType :: FillConversionPath +// +// Traces backwards from the target type to the original type and fills in +// the conversions necessary to get between them. slots must point to an +// array large enough to contain the entire path. +// +//========================================================================== + +void PType::FillConversionPath(const PType::Conversion **slots) +{ + for (PType *node = this; node->Distance >= 0; node = node->PredType) + { + assert(node->PredType != NULL); + slots[node->Distance] = &node->PredType->Conversions[node->PredConv]; + } +} + +//========================================================================== +// +// PType :: VisitQueue :: Push +// +//========================================================================== + +void PType::VisitQueue::Push(PType *type) +{ + Queue[In] = type; + Advance(In); + assert(!IsEmpty() && "Queue overflowed"); +} + +//========================================================================== +// +// PType :: VisitQueue :: Pop +// +//========================================================================== + +PType *PType::VisitQueue::Pop() +{ + if (IsEmpty()) + { + return NULL; + } + PType *node = Queue[Out]; + Advance(Out); + return node; +} + +//========================================================================== +// +// PType :: VisitedNodeSet :: Insert +// +//========================================================================== + +void PType::VisitedNodeSet::Insert(PType *node) +{ + assert(!Check(node) && "Node was already inserted"); + size_t buck = Hash(node) & (countof(Buckets) - 1); + node->VisitNext = Buckets[buck]; + Buckets[buck] = node; +} + +//========================================================================== +// +// PType :: VisitedNodeSet :: Check +// +//========================================================================== + +bool PType::VisitedNodeSet::Check(const PType *node) +{ + size_t buck = Hash(node) & (countof(Buckets) - 1); + for (const PType *probe = Buckets[buck]; probe != NULL; probe = probe->VisitNext) + { + if (probe == node) + { + return true; + } + } + return false; +} + //========================================================================== // // PType :: SetValue diff --git a/src/dobjtype.h b/src/dobjtype.h index 2861b1da2..a282d0790 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -113,6 +113,7 @@ private: // Map * * // Prototype *+ *+ +struct ZCC_ExprConstant; class PClassType; class PType : public DObject { @@ -128,6 +129,15 @@ public: typedef PClassType MetaClass; MetaClass *GetClass() const; + struct Conversion + { + Conversion(PType *target, void (*convert)(ZCC_ExprConstant *, class FSharedStringArena &)) + : TargetType(target), ConvertConstant(convert) {} + + PType *TargetType; + void (*ConvertConstant)(ZCC_ExprConstant *val, class FSharedStringArena &strdump); + }; + unsigned int Size; // this type's size unsigned int Align; // this type's preferred alignment PType *HashNext; // next type in this type table @@ -136,6 +146,10 @@ public: PType(unsigned int size, unsigned int align); virtual ~PType(); + bool AddConversion(PType *target, void (*convertconst)(ZCC_ExprConstant *, class FSharedStringArena &)); + + int FindConversion(PType *target, const Conversion **slots, int numslots); + // Sets the value of a variable of this type at (addr) virtual void SetValue(void *addr, int val); @@ -163,6 +177,54 @@ public: virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; static void StaticInit(); + +private: + // Stuff for type conversion searches + class VisitQueue + { + public: + VisitQueue() : In(0), Out(0) {} + void Push(PType *type); + PType *Pop(); + bool IsEmpty() { return In == Out; } + + private: + // This is a fixed-sized ring buffer. + PType *Queue[64]; + int In, Out; + + void Advance(int &ptr) + { + ptr = (ptr + 1) & (countof(Queue) - 1); + } + }; + + class VisitedNodeSet + { + public: + VisitedNodeSet() { memset(Buckets, 0, sizeof(Buckets)); } + void Insert(PType *node); + bool Check(const PType *node); + + private: + PType *Buckets[32]; + + size_t Hash(const PType *type) { return size_t(type) >> 4; } + }; + + TArray<Conversion> Conversions; + PType *PredType; + PType *VisitNext; + short PredConv; + short Distance; + + void MarkPred(PType *pred, int conv, int dist) + { + PredType = pred; + PredConv = conv; + Distance = dist; + } + void FillConversionPath(const Conversion **slots); }; // Not-really-a-type types -------------------------------------------------- From dbc9fd6c0e923ab4ce5ca1b820bbe72884cb3d09 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 23 Oct 2013 22:46:34 -0500 Subject: [PATCH 174/232] Pad PSymbolConstNumeric to ensure it's the same size as PSymbolConstString --- src/dobjtype.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dobjtype.h b/src/dobjtype.h index a282d0790..b66f68340 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -744,6 +744,7 @@ public: { int Value; double Float; + void *Pad; }; PSymbolConstNumeric(FName name, PType *type=NULL) : PSymbolConst(name, type) {} From d0968af9a6c02ffd4f18c3c14ba2bcdb988b876a Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 23 Oct 2013 22:49:02 -0500 Subject: [PATCH 175/232] Separate the AST from the parser state. --- src/zscript/zcc-parse.lemon | 12 +----------- src/zscript/zcc_parser.cpp | 21 +++++++++++++++++++++ src/zscript/zcc_parser.h | 34 +++++++++++++++++++++++----------- 3 files changed, 45 insertions(+), 22 deletions(-) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index a3c9d1141..ae31a1e09 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -2,19 +2,9 @@ { // Allocates a new AST node off the parse state's arena. #define NEW_AST_NODE(type,name,tok) \ - ZCC_##type *name = static_cast<ZCC_##type *>(InitNode(sizeof(ZCC_##type), AST_##type, stat)); \ + ZCC_##type *name = static_cast<ZCC_##type *>(stat->InitNode(sizeof(ZCC_##type), AST_##type)); \ SetNodeLine(name, tok) -static ZCC_TreeNode *InitNode(size_t size, EZCCTreeNodeType type, ZCCParseState *stat) -{ - ZCC_TreeNode *node = (ZCC_TreeNode *)stat->SyntaxArena.Alloc(size); - node->SiblingNext = node; - node->SiblingPrev = node; - node->NodeType = type; - node->SourceName = stat->Strings.Alloc(stat->sc.ScriptName); - return node; -} - static void SetNodeLine(ZCC_TreeNode *name, ZCCToken &tok) { name->SourceLoc = tok.SourceLoc; diff --git a/src/zscript/zcc_parser.cpp b/src/zscript/zcc_parser.cpp index 766f28c2a..32127ed46 100644 --- a/src/zscript/zcc_parser.cpp +++ b/src/zscript/zcc_parser.cpp @@ -297,3 +297,24 @@ static FString ZCCTokenName(int terminal) } return FScanner::TokenName(sc_token); } + +ZCC_TreeNode *ZCC_AST::InitNode(size_t size, EZCCTreeNodeType type, ZCC_TreeNode *basis) +{ + ZCC_TreeNode *node = (ZCC_TreeNode *)SyntaxArena.Alloc(size); + node->SiblingNext = node; + node->SiblingPrev = node; + node->NodeType = type; + if (basis != NULL) + { + node->SourceName = basis->SourceName; + node->SourceLoc = basis->SourceLoc; + } + return node; +} + +ZCC_TreeNode *ZCCParseState::InitNode(size_t size, EZCCTreeNodeType type) +{ + ZCC_TreeNode *node = ZCC_AST::InitNode(size, type, NULL); + node->SourceName = Strings.Alloc(sc.ScriptName); + return node; +} diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index f5131e839..50e75fd94 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -1,15 +1,7 @@ -struct ZCCParseState -{ - ZCCParseState(FScanner &scanner) : sc(scanner) - { - TopNode = NULL; - } +#ifndef ZCC_PARSER_H +#define ZCC_PARSER_H - FScanner ≻ - FSharedStringArena Strings; - FMemArena SyntaxArena; - struct ZCC_TreeNode *TopNode; -}; +#include "memarena.h" struct ZCCToken { @@ -500,3 +492,23 @@ struct ZCC_FuncDeclarator : ZCC_Declarator }; FString ZCC_PrintAST(ZCC_TreeNode *root); + +struct ZCC_AST +{ + ZCC_AST() : TopNode(NULL) {} + ZCC_TreeNode *InitNode(size_t size, EZCCTreeNodeType type, ZCC_TreeNode *basis); + + FSharedStringArena Strings; + FMemArena SyntaxArena; + struct ZCC_TreeNode *TopNode; +}; + +struct ZCCParseState : public ZCC_AST +{ + ZCCParseState(FScanner &scanner) : sc(scanner) {} + ZCC_TreeNode *InitNode(size_t size, EZCCTreeNodeType type); + + FScanner ≻ +}; + +#endif From 850055a766b6232a24dc4b65bcc0fb0c571288e5 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 23 Oct 2013 23:06:32 -0500 Subject: [PATCH 176/232] Add evaluation of constant unary and binary expressions - Added ZCCCompiler class as a place to generate IR and symbols from an AST. Right now, all it does is simplify constant expressions into constant values. - Do type promotion on the AST where appropriate. - Added true and false tokens to the parser driver. --- src/CMakeLists.txt | 2 + src/zscript/ast.cpp | 54 +-- src/zscript/zcc_compile.cpp | 393 +++++++++++++++++++++ src/zscript/zcc_compile.h | 48 +++ src/zscript/zcc_errors.h | 8 + src/zscript/zcc_expr.cpp | 672 ++++++++++++++++++++++++++++++++++++ src/zscript/zcc_exprlist.h | 56 +++ src/zscript/zcc_parser.cpp | 13 +- src/zscript/zcc_parser.h | 107 +++--- zdoom.vcproj | 20 ++ 10 files changed, 1265 insertions(+), 108 deletions(-) create mode 100644 src/zscript/zcc_compile.cpp create mode 100644 src/zscript/zcc_compile.h create mode 100644 src/zscript/zcc_errors.h create mode 100644 src/zscript/zcc_expr.cpp create mode 100644 src/zscript/zcc_exprlist.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ee814c138..152425353 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -952,6 +952,8 @@ add_executable( zdoom WIN32 zscript/vmdisasm.cpp zscript/vmexec.cpp zscript/vmframe.cpp + zscript/zcc_compile.cpp + zscript/zcc_expr.cpp zscript/zcc_parser.cpp autozend.cpp ) diff --git a/src/zscript/ast.cpp b/src/zscript/ast.cpp index ea7862a94..77335fcde 100644 --- a/src/zscript/ast.cpp +++ b/src/zscript/ast.cpp @@ -442,61 +442,11 @@ static void PrintClassType(FLispString &out, ZCC_TreeNode *node) static void OpenExprType(FLispString &out, EZCCExprType type) { - static const char *const types[] = - { - "nil", - "id", - "super", - "self", - "const", - "func-call", - "array-access", - "member-access", - "post-inc", - "post-dec", - "pre-inc", - "pre-dec", - "negate", - "anti-negate", - "bit-not", - "bool-not", - "size-of", - "align-of", - "add", - "sub", - "mul", - "div", - "mod", - "pow", - "cross-product", - "dot-product", - "left-shift", - "right-shift", - "concat", - "lt", - "gt", - "lteq", - "gteq", - "ltgteq", - "is", - "eqeq", - "neq", - "apreq", - "bit-and", - "bit-or", - "bit-xor", - "bool-and", - "bool-or", - "scope", - "trinary", - }; - assert(countof(types) == PEX_COUNT_OF); - char buf[32]; - if (unsigned(type) < countof(types)) + if (unsigned(type) < PEX_COUNT_OF) { - mysnprintf(buf, countof(buf), "expr-%s", types[type]); + mysnprintf(buf, countof(buf), "expr-%s", ZCC_OpInfo[type].OpName); } else { diff --git a/src/zscript/zcc_compile.cpp b/src/zscript/zcc_compile.cpp new file mode 100644 index 000000000..86f2d3ea2 --- /dev/null +++ b/src/zscript/zcc_compile.cpp @@ -0,0 +1,393 @@ +#include "dobject.h" +#include "sc_man.h" +#include "c_console.h" +#include "c_dispatch.h" +#include "w_wad.h" +#include "cmdlib.h" +#include "m_alloc.h" +#include "zcc_parser.h" +#include "zcc_compile.h" +#include "v_text.h" +#include "gdtoa.h" + +//========================================================================== +// +// ZCCCompiler Constructor +// +//========================================================================== + +ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols) +: Outer(_outer), Symbols(_symbols), AST(ast), ErrorCount(0), WarnCount(0) +{ + // Group top-level nodes by type + if (ast.TopNode != NULL) + { + ZCC_TreeNode *node = ast.TopNode; + do + { + switch (node->NodeType) + { + case AST_Class: Classes.Push(static_cast<ZCC_Class *>(node)); break; + case AST_Struct: Structs.Push(static_cast<ZCC_Struct *>(node)); break; + case AST_Enum: break; + case AST_EnumTerminator:break; + case AST_ConstantDef: Constants.Push(static_cast<ZCC_ConstantDef *>(node)); break; + default: assert(0 && "Unhandled AST node type"); break; + } + node = node->SiblingNext; + } + while (node != ast.TopNode); + } +} + +//========================================================================== +// +// ZCCCompiler :: Message +// +// Prints a warning or error message, and increments the appropriate +// counter. +// +//========================================================================== + +void ZCCCompiler::Message(ZCC_TreeNode *node, EZCCError errnum, const char *msg, ...) +{ + FString composed; + + composed.Format("%s%s, line %d: ", + errnum & ZCCERR_ERROR ? TEXTCOLOR_RED : TEXTCOLOR_ORANGE, + node->SourceName->GetChars(), node->SourceLoc); + + va_list argptr; + va_start(argptr, msg); + composed.VAppendFormat(msg, argptr); + va_end(argptr); + + composed += '\n'; + PrintString(PRINT_HIGH, composed); + + if (errnum & ZCCERR_ERROR) + { + ErrorCount++; + } + else + { + WarnCount++; + } +} + +//========================================================================== +// +// ZCCCompiler :: Compile +// +// Compile everything defined at this level. +// +//========================================================================== + +int ZCCCompiler::Compile() +{ + CompileConstants(); + return ErrorCount; +} + +//========================================================================== +// +// ZCCCompiler :: CompileConstants +// +// Make symbols from every constant defined at this level. +// +//========================================================================== + +void ZCCCompiler::CompileConstants() +{ + for (unsigned i = 0; i < Constants.Size(); ++i) + { + ZCC_ConstantDef *def = Constants[i]; + if (def->Symbol == NULL) + { + PSymbolConst *sym = CompileConstant(def); + if (NULL == Symbols.AddSymbol(sym)) + { + Message(Constants[i], ERR_symbol_redefinition, "Redefinition of symbol '%s'", FName(def->Name).GetChars()); + } + } + } +} + +//========================================================================== +// +// ZCCCompiler :: CompileConstant +// +// For every constant definition, evaluate its value (which should result +// in a constant), and create a symbol for it. Simplify() uses recursion +// to resolve constants used before their declarations. +// +//========================================================================== + +PSymbolConst *ZCCCompiler::CompileConstant(ZCC_ConstantDef *def) +{ + assert(def->Symbol == NULL); + + def->Symbol = (PSymbolConst *)(void *)1; // mark as being defined (avoid recursion) + ZCC_Expression *val = Simplify(def->Value); + def->Value = val; + PSymbolConst *sym = NULL; + if (val->NodeType == AST_ExprConstant) + { + ZCC_ExprConstant *cval = static_cast<ZCC_ExprConstant *>(val); + if (cval->Type == TypeString) + { + sym = new PSymbolConstString(def->Name, *(cval->StringVal)); + } + else if (cval->Type->IsA(RUNTIME_CLASS(PInt))) + { + sym = new PSymbolConstNumeric(def->Name, cval->Type, cval->IntVal); + } + else if (cval->Type->IsA(RUNTIME_CLASS(PFloat))) + { + sym = new PSymbolConstNumeric(def->Name, cval->Type, cval->DoubleVal); + } + else + { + Message(def->Value, ERR_bad_const_def_type, "Bad type for constant definiton"); + } + } + else + { + Message(def->Value, ERR_const_def_not_constant, "Constant definition requires a constant value"); + } + if (sym == NULL) + { + // Create a dummy constant so we don't make any undefined value warnings. + sym = new PSymbolConstNumeric(def->Name, TypeError, 0); + } + def->Symbol = sym; + return sym; +} + + +//========================================================================== +// +// ZCCCompiler :: Simplify +// +// For an expression, +// Evaluate operators whose arguments are both constants, replacing it +// with a new constant. +// For a binary operator with one constant argument, put it on the right- +// hand operand, where permitted. +// Perform automatic type promotion. +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::Simplify(ZCC_Expression *root) +{ + if (root->Operation == PEX_ID) + { + return IdentifyIdentifier(static_cast<ZCC_ExprID *>(root)); + } + else if (IsUnaryOp(root->Operation)) + { + return SimplifyUnary(static_cast<ZCC_ExprUnary *>(root)); + } + else if (IsBinaryOp(root->Operation)) + { + return SimplifyBinary(static_cast<ZCC_ExprBinary *>(root)); + } + return root; +} + +//========================================================================== +// +// ZCCCompiler :: SimplifyUnary +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::SimplifyUnary(ZCC_ExprUnary *unary) +{ + unary->Operand = Simplify(unary->Operand); + ZCC_OpProto *op = PromoteUnary(unary->Operation, unary->Operand); + if (op == NULL) + { // Oh, poo! + unary->Type = TypeError; + } + else if (unary->Operand->Operation == PEX_ConstValue) + { + return op->EvalConst1(static_cast<ZCC_ExprConstant *>(unary->Operand)); + } + return unary; +} + +//========================================================================== +// +// ZCCCompiler :: SimplifyBinary +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::SimplifyBinary(ZCC_ExprBinary *binary) +{ + binary->Left = Simplify(binary->Left); + binary->Right = Simplify(binary->Right); + ZCC_OpProto *op = PromoteBinary(binary->Operation, binary->Left, binary->Right); + if (op == NULL) + { + binary->Type = TypeError; + } + else if (binary->Left->Operation == PEX_ConstValue && + binary->Right->Operation == PEX_ConstValue) + { + return op->EvalConst2(static_cast<ZCC_ExprConstant *>(binary->Left), + static_cast<ZCC_ExprConstant *>(binary->Right), AST.Strings); + } + return binary; +} + +//========================================================================== +// +// ZCCCompiler :: PromoteUnary +// +// Converts the operand into a format preferred by the operator. +// +//========================================================================== + +ZCC_OpProto *ZCCCompiler::PromoteUnary(EZCCExprType op, ZCC_Expression *&expr) +{ + if (expr->Type == TypeError) + { + return NULL; + } + const PType::Conversion *route[CONVERSION_ROUTE_SIZE]; + int routelen = countof(route); + ZCC_OpProto *proto = ZCC_OpInfo[op].FindBestProto(expr->Type, route, routelen); + + if (proto != NULL) + { + expr = ApplyConversion(expr, route, routelen); + } + return proto; +} + +//========================================================================== +// +// ZCCCompiler :: PromoteBinary +// +// Converts the operands into a format (hopefully) compatible with the +// operator. +// +//========================================================================== + +ZCC_OpProto *ZCCCompiler::PromoteBinary(EZCCExprType op, ZCC_Expression *&left, ZCC_Expression *&right) +{ + // If either operand is of type 'error', the result is also 'error' + if (left->Type == TypeError || right->Type == TypeError) + { + return NULL; + } + const PType::Conversion *route1[CONVERSION_ROUTE_SIZE], *route2[CONVERSION_ROUTE_SIZE]; + int route1len = countof(route1), route2len = countof(route2); + ZCC_OpProto *proto = ZCC_OpInfo[op].FindBestProto(left->Type, route1, route1len, right->Type, route2, route2len); + if (proto != NULL) + { + left = ApplyConversion(left, route1, route1len); + right = ApplyConversion(right, route2, route2len); + } + return proto; +} + +//========================================================================== +// +// ZCCCompiler :: ApplyConversion +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::ApplyConversion(ZCC_Expression *expr, const PType::Conversion **route, int routelen) +{ + for (int i = 0; i < routelen; ++i) + { + if (expr->Operation != PEX_ConstValue) + { + expr = AddCastNode(route[i]->TargetType, expr); + } + else + { + route[i]->ConvertConstant(static_cast<ZCC_ExprConstant *>(expr), AST.Strings); + } + } + return expr; +} + +//========================================================================== +// +// ZCCCompiler :: AddCastNode +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::AddCastNode(PType *type, ZCC_Expression *expr) +{ + assert(expr->Operation != PEX_ConstValue && "Expression must not be constant"); + // TODO: add a node here + return expr; +} + +//========================================================================== +// +// ZCCCompiler :: IdentifyIdentifier +// +// Returns a node that represents what the identifer stands for. +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::IdentifyIdentifier(ZCC_ExprID *idnode) +{ + // First things first: Check the symbol table. + PSymbol *sym; + if (NULL != (sym = Symbols.FindSymbol(idnode->Identifier, true))) + { + if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) + { + return NodeFromSymbolConst(static_cast<PSymbolConst *>(sym), idnode); + } + } + else + { + } + // Identifier didn't refer to anything good, so type error it. + idnode->Type = TypeError; + idnode->Operation = PEX_Nil; + return idnode; +} + +//========================================================================== +// +// ZCCCompiler :: NodeFromSymoblConst +// +// Returns a new AST constant node with the symbol's content. +// +//========================================================================== + +ZCC_ExprConstant *ZCCCompiler::NodeFromSymbolConst(PSymbolConst *sym, ZCC_ExprID *idnode) +{ + ZCC_ExprConstant *val = static_cast<ZCC_ExprConstant *>(AST.InitNode(sizeof(*val), AST_ExprConstant, idnode)); + val->Operation = PEX_ConstValue; + if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConstString))) + { + val->StringVal = AST.Strings.Alloc(static_cast<PSymbolConstString *>(sym)->Str); + val->Type = TypeString; + } + else + { + val->Type = sym->ValueType; + if (val->Type != TypeError) + { + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric))); + if (sym->ValueType->IsKindOf(RUNTIME_CLASS(PInt))) + { + val->IntVal = static_cast<PSymbolConstNumeric *>(sym)->Value; + } + else + { + assert(sym->ValueType->IsKindOf(RUNTIME_CLASS(PFloat))); + val->DoubleVal = static_cast<PSymbolConstNumeric *>(sym)->Float; + } + } + } + return val; +} diff --git a/src/zscript/zcc_compile.h b/src/zscript/zcc_compile.h new file mode 100644 index 000000000..78632e444 --- /dev/null +++ b/src/zscript/zcc_compile.h @@ -0,0 +1,48 @@ +#ifndef ZCC_COMPILE_H +#define ZCC_COMPILE_H + +#include "zcc_errors.h" + +class ZCCCompiler +{ +public: + ZCCCompiler(ZCC_AST &tree, DObject *outer, PSymbolTable &symbols); + int Compile(); + +private: + void CompileConstants(); + PSymbolConst *CompileConstant(ZCC_ConstantDef *def); + + TArray<ZCC_ConstantDef *> Constants; + TArray<ZCC_Struct *> Structs; + TArray<ZCC_Class *> Classes; + + ZCC_Expression *Simplify(ZCC_Expression *root); + ZCC_Expression *SimplifyUnary(ZCC_ExprUnary *unary); + ZCC_Expression *SimplifyBinary(ZCC_ExprBinary *binary); + ZCC_OpProto *PromoteUnary(EZCCExprType op, ZCC_Expression *&expr); + ZCC_OpProto *PromoteBinary(EZCCExprType op, ZCC_Expression *&left, ZCC_Expression *&right); + + void PromoteToInt(ZCC_Expression *&expr); + void PromoteToUInt(ZCC_Expression *&expr); + void PromoteToDouble(ZCC_Expression *&expr); + void PromoteToString(ZCC_Expression *&expr); + + ZCC_Expression *ApplyConversion(ZCC_Expression *expr, const PType::Conversion **route, int routelen); + ZCC_Expression *AddCastNode(PType *type, ZCC_Expression *expr); + + ZCC_Expression *IdentifyIdentifier(ZCC_ExprID *idnode); + ZCC_ExprConstant *NodeFromSymbolConst(PSymbolConst *sym, ZCC_ExprID *idnode); + + void Message(ZCC_TreeNode *node, EZCCError errnum, const char *msg, ...); + + DObject *Outer; + PSymbolTable &Symbols; + ZCC_AST &AST; + int ErrorCount; + int WarnCount; +}; + +void ZCC_InitConversions(); + +#endif diff --git a/src/zscript/zcc_errors.h b/src/zscript/zcc_errors.h new file mode 100644 index 000000000..bfb617b63 --- /dev/null +++ b/src/zscript/zcc_errors.h @@ -0,0 +1,8 @@ +#define ZCCERR_ERROR 0x40000000 + +enum EZCCError +{ + ERR_const_def_not_constant = 20000 | ZCCERR_ERROR, + ERR_bad_const_def_type = 20001 | ZCCERR_ERROR, + ERR_symbol_redefinition = 20002 | ZCCERR_ERROR, +}; diff --git a/src/zscript/zcc_expr.cpp b/src/zscript/zcc_expr.cpp new file mode 100644 index 000000000..9d5f1e683 --- /dev/null +++ b/src/zscript/zcc_expr.cpp @@ -0,0 +1,672 @@ +#include "dobject.h" +#include "sc_man.h" +#include "c_console.h" +#include "c_dispatch.h" +#include "w_wad.h" +#include "cmdlib.h" +#include "m_alloc.h" +#include "zcc_parser.h" +#include "templates.h" + +#define luai_nummod(a,b) ((a) - floor((a)/(b))*(b)) + +extern PSymbolTable GlobalSymbols; + +ZCC_OpInfoType ZCC_OpInfo[PEX_COUNT_OF] = +{ +#define xx(a,n) { n, #a, NULL }, +#include "zcc_exprlist.h" +}; + +// Structures used for initializing operator overloads +struct OpProto1 +{ + EZCCExprType Op; + PType **Type; + EvalConst1op EvalConst; +}; + +struct OpProto2 +{ + EZCCExprType Op; + PType **Res, **Ltype, **Rtype; + EvalConst2op EvalConst; +}; + +void ZCC_OpInfoType::AddProto(PType *res, PType *optype, EvalConst1op evalconst) +{ + ZCC_OpProto *proto = new ZCC_OpProto(res, optype, NULL); + proto->EvalConst1 = evalconst; + proto->Next = Protos; + Protos = proto; +} + +void ZCC_OpInfoType::AddProto(PType *res, PType *ltype, PType *rtype, EvalConst2op evalconst) +{ + assert(ltype != NULL); + ZCC_OpProto *proto = new ZCC_OpProto(res, ltype, rtype); + proto->EvalConst2 = evalconst; + proto->Next = Protos; + Protos = proto; +} + +//========================================================================== +// +// ZCC_OpInfoType :: FindBestProto (Unary) +// +// Finds the "best" prototype for this operand type. Best is defined as the +// one that requires the fewest conversions. Also returns the conversion +// route necessary to get from the input type to the desired type. +// +//========================================================================== + +ZCC_OpProto *ZCC_OpInfoType::FindBestProto(PType *optype, const PType::Conversion **route, int &numslots) +{ + assert(optype != NULL); + + const PType::Conversion *routes[2][CONVERSION_ROUTE_SIZE]; + const PType::Conversion **best_route = NULL; + int cur_route = 0; + ZCC_OpProto *best_proto = NULL; + int best_dist = INT_MAX; + + // Find the best prototype. + for (ZCC_OpProto *proto = Protos; best_dist != 0 && proto != NULL; proto = proto->Next) + { + if (proto->Type2 != NULL) + { // Not a unary prototype. + continue; + } + int dist = optype->FindConversion(proto->Type1, routes[cur_route], CONVERSION_ROUTE_SIZE); + if (dist >= 0 && dist < best_dist) + { + best_dist = dist; + best_proto = proto; + best_route = routes[cur_route]; + cur_route ^= 1; + } + } + // Copy best conversion route to the caller's array. + if (best_route != NULL && route != NULL && numslots > 0) + { + numslots = MIN(numslots, best_dist); + if (numslots > 0) + { + memcpy(route, best_route, sizeof(*route) * numslots); + } + } + return best_proto; +} + +//========================================================================== +// +// ZCC_OpInfoType :: FindBestProto (Binary) +// +// Finds the "best" prototype for the given operand types. Here, best is +// defined as the one that requires the fewest conversions for *one* of the +// operands. For prototypes with matching distances, the first one found +// is used. ZCC_InitOperators() initializes the prototypes in order such +// that this will result in the precedences: double > uint > int +// +//========================================================================== + +ZCC_OpProto *ZCC_OpInfoType::FindBestProto( + PType *left, const PType::Conversion **route1, int &numslots1, + PType *right, const PType::Conversion **route2, int &numslots2) +{ + assert(left != NULL && right != NULL); + + const PType::Conversion *routes[2][2][CONVERSION_ROUTE_SIZE]; + const PType::Conversion **best_route1 = NULL, **best_route2 = NULL; + int cur_route1 = 0, cur_route2 = 0; + int best_dist1 = INT_MAX, best_dist2 = INT_MAX; + + ZCC_OpProto *best_proto = NULL; + int best_low_dist = INT_MAX; + + for (ZCC_OpProto *proto = Protos; best_low_dist != 0 && proto != NULL; proto = proto->Next) + { + if (proto->Type2 == NULL) + { // Not a binary prototype + continue; + } + int dist1 = left->FindConversion(proto->Type1, routes[0][cur_route1], CONVERSION_ROUTE_SIZE); + int dist2 = right->FindConversion(proto->Type2, routes[1][cur_route2], CONVERSION_ROUTE_SIZE); + if (dist1 < 0 || dist2 < 0) + { // one or both operator types are unreachable + continue; + } + int dist = MIN(dist1, dist2); + if (dist < best_low_dist) + { + best_low_dist = dist; + best_proto = proto; + best_dist1 = dist1; + best_dist2 = dist2; + best_route1 = routes[0][cur_route1]; + best_route2 = routes[1][cur_route2]; + cur_route1 ^= 1; + cur_route2 ^= 1; + } + } + // Copy best conversion route to the caller's arrays. + if (best_route1 != NULL && route1 != NULL && numslots1 > 0) + { + numslots1 = MIN(numslots1, best_dist1); + if (numslots1 > 0) + { + memcpy(route1, best_route1, sizeof(*route1) * numslots1); + } + } + if (best_route2 != NULL && route2 != NULL && numslots2 > 0) + { + numslots2 = MIN(numslots2, best_dist2); + if (numslots2 > 0) + { + memcpy(route2, best_route2, sizeof(*route2) * numslots2); + } + } + return best_proto; +} + +static ZCC_ExprConstant *EvalIncFloat64(ZCC_ExprConstant *val) +{ + val->DoubleVal++; + return val; +} + +static ZCC_ExprConstant *EvalIncInt32(ZCC_ExprConstant *val) +{ + val->IntVal++; + return val; +} + +static ZCC_ExprConstant *EvalDecFloat64(ZCC_ExprConstant *val) +{ + val->DoubleVal--; + return val; +} + +static ZCC_ExprConstant *EvalDecInt32(ZCC_ExprConstant *val) +{ + val->IntVal--; + return val; +} + +static ZCC_ExprConstant *EvalNegateFloat64(ZCC_ExprConstant *val) +{ + val->DoubleVal = -val->DoubleVal; + return val; +} + +static ZCC_ExprConstant *EvalNegateInt32(ZCC_ExprConstant *val) +{ + val->IntVal = -val->IntVal; + return val; +} + +static ZCC_ExprConstant *EvalIdentity(ZCC_ExprConstant *val) +{ + return val; +} + +static ZCC_ExprConstant *EvalBitNot(ZCC_ExprConstant *val) +{ + val->IntVal = ~val->IntVal; + return val; +} + +static ZCC_ExprConstant *EvalBoolNot(ZCC_ExprConstant *val) +{ + val->IntVal = !val->IntVal; + return val; +} + +static ZCC_ExprConstant *EvalAddFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->DoubleVal += r->DoubleVal; + return l; +} + +static ZCC_ExprConstant *EvalAddInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal += r->IntVal; + return l; +} + +static ZCC_ExprConstant *EvalSubFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->DoubleVal -= r->DoubleVal; + return l; +} + +static ZCC_ExprConstant *EvalSubInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal -= r->IntVal; + return l; +} + +static ZCC_ExprConstant *EvalMulFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->DoubleVal *= r->DoubleVal; + return l; +} + +static ZCC_ExprConstant *EvalMulUInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->UIntVal *= r->UIntVal; + return l; +} + +static ZCC_ExprConstant *EvalMulSInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal *= r->IntVal; + return l; +} + +static ZCC_ExprConstant *EvalDivFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->DoubleVal /= r->DoubleVal; + return l; +} + +static ZCC_ExprConstant *EvalDivUInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->UIntVal /= r->UIntVal; + return l; +} + +static ZCC_ExprConstant *EvalDivSInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal /= r->IntVal; + return l; +} + +static ZCC_ExprConstant *EvalModFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->DoubleVal = luai_nummod(l->DoubleVal, r->DoubleVal); + return l; +} + +static ZCC_ExprConstant *EvalModUInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->UIntVal %= r->UIntVal; + return l; +} + +static ZCC_ExprConstant *EvalModSInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal %= r->IntVal; + return l; +} + +static ZCC_ExprConstant *EvalPow(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->DoubleVal = pow(l->DoubleVal, r->DoubleVal); + return l; +} + +static ZCC_ExprConstant *EvalConcat(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &strings) +{ + FString str = *l->StringVal + *r->StringVal; + l->StringVal = strings.Alloc(str); + return l; +} + +static ZCC_ExprConstant *EvalBitAnd(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal &= r->IntVal; + return l; +} + +static ZCC_ExprConstant *EvalBitOr(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal |= r->IntVal; + return l; +} + +static ZCC_ExprConstant *EvalBitXor(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal ^= r->IntVal; + return l; +} + +static ZCC_ExprConstant *EvalBoolAnd(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->IntVal && r->IntVal; + return l; +} + +static ZCC_ExprConstant *EvalBoolOr(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->IntVal || r->IntVal; + return l; +} + +static ZCC_ExprConstant *EvalSHL(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal <<= r->UIntVal; + return l; +} + +static ZCC_ExprConstant *EvalSHR_S(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal >>= r->UIntVal; + return l; +} + +static ZCC_ExprConstant *EvalSHR_U(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->UIntVal >>= r->UIntVal; + return l; +} + +static ZCC_ExprConstant *EvalLTSInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->IntVal < r->IntVal; + l->Type = TypeBool; + return l; +} + +static ZCC_ExprConstant *EvalLTUInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->UIntVal < r->UIntVal; + l->Type = TypeBool; + return l; +} + +static ZCC_ExprConstant *EvalLTFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->DoubleVal < r->DoubleVal; + l->Type = TypeBool; + return l; +} + +static ZCC_ExprConstant *EvalLTEQSInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->IntVal <= r->IntVal; + l->Type = TypeBool; + return l; +} + +static ZCC_ExprConstant *EvalLTEQUInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->UIntVal <= r->UIntVal; + l->Type = TypeBool; + return l; +} + +static ZCC_ExprConstant *EvalLTEQFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->DoubleVal <= r->DoubleVal; + l->Type = TypeBool; + return l; +} + +static ZCC_ExprConstant *EvalEQEQSInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->IntVal == r->IntVal; + l->Type = TypeBool; + return l; +} + +static ZCC_ExprConstant *EvalEQEQUInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->UIntVal == r->UIntVal; + l->Type = TypeBool; + return l; +} + +static ZCC_ExprConstant *EvalEQEQFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->DoubleVal == r->DoubleVal; + l->Type = TypeBool; + return l; +} + +static ZCC_ExprConstant *EvalLTGTEQSInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->IntVal < r->IntVal ? -1 : l->IntVal == r->IntVal ? 0 : 1; + return l; +} + +static ZCC_ExprConstant *EvalLTGTEQUInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->UIntVal < r->UIntVal ? -1 : l->UIntVal == r->UIntVal ? 0 : 1; + l->Type = TypeSInt32; + return l; +} + +static ZCC_ExprConstant *EvalLTGTEQFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->DoubleVal < r->DoubleVal ? -1 : l->DoubleVal == r->DoubleVal ? 0 : 1; + l->Type = TypeSInt32; + return l; +} + +void ZCC_InitOperators() +{ + // Prototypes are added from lowest to highest conversion precedence. + + // Unary operators + static const OpProto1 UnaryOpInit[] = + { + { PEX_PostInc , (PType **)&TypeSInt32, EvalIdentity }, + { PEX_PostInc , (PType **)&TypeUInt32, EvalIdentity }, + { PEX_PostInc , (PType **)&TypeFloat64, EvalIdentity }, + + { PEX_PostDec , (PType **)&TypeSInt32, EvalIdentity }, + { PEX_PostDec , (PType **)&TypeUInt32, EvalIdentity }, + { PEX_PostDec , (PType **)&TypeFloat64, EvalIdentity }, + + { PEX_PreInc , (PType **)&TypeSInt32, EvalIncInt32 }, + { PEX_PreInc , (PType **)&TypeUInt32, EvalIncInt32 }, + { PEX_PreInc , (PType **)&TypeFloat64, EvalIncFloat64 }, + + { PEX_PreDec , (PType **)&TypeSInt32, EvalDecInt32 }, + { PEX_PreDec , (PType **)&TypeUInt32, EvalDecInt32 }, + { PEX_PreDec , (PType **)&TypeFloat64, EvalDecFloat64 }, + + { PEX_Negate , (PType **)&TypeSInt32, EvalNegateInt32 }, + { PEX_Negate , (PType **)&TypeFloat64, EvalNegateFloat64 }, + + { PEX_AntiNegate , (PType **)&TypeSInt32, EvalIdentity }, + { PEX_AntiNegate , (PType **)&TypeUInt32, EvalIdentity }, + { PEX_AntiNegate , (PType **)&TypeFloat64, EvalIdentity }, + + { PEX_BitNot , (PType **)&TypeSInt32, EvalBitNot }, + { PEX_BitNot , (PType **)&TypeUInt32, EvalBitNot }, + + { PEX_BoolNot , (PType **)&TypeBool, EvalBoolNot }, + }; + for (size_t i = 0; i < countof(UnaryOpInit); ++i) + { + ZCC_OpInfo[UnaryOpInit[i].Op].AddProto(*UnaryOpInit[i].Type, *UnaryOpInit[i].Type, UnaryOpInit[i].EvalConst); + } + + // Binary operators + static const OpProto2 BinaryOpInit[] = + { + { PEX_Add , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalAddInt32 }, + { PEX_Add , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalAddInt32 }, + { PEX_Add , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalAddFloat64 }, + + { PEX_Sub , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalSubInt32 }, + { PEX_Sub , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalSubInt32 }, + { PEX_Sub , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalSubFloat64 }, + + { PEX_Mul , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalMulSInt32 }, + { PEX_Mul , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalMulUInt32 }, + { PEX_Mul , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalMulFloat64 }, + + { PEX_Div , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalDivSInt32 }, + { PEX_Div , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalDivUInt32 }, + { PEX_Div , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalDivFloat64 }, + + { PEX_Mod , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalModSInt32 }, + { PEX_Mod , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalModUInt32 }, + { PEX_Mod , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalModFloat64 }, + + { PEX_Pow , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalPow }, + + { PEX_Concat , (PType **)&TypeString, (PType **)&TypeString, (PType **)&TypeString, EvalConcat }, + + { PEX_BitAnd , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalBitAnd }, + { PEX_BitAnd , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalBitAnd }, + + { PEX_BitOr , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalBitOr }, + { PEX_BitOr , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalBitOr }, + + { PEX_BitXor , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalBitXor }, + { PEX_BitXor , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalBitXor }, + + { PEX_BoolAnd , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalBoolAnd }, + { PEX_BoolAnd , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalBoolAnd }, + + { PEX_BoolOr , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalBoolOr }, + { PEX_BoolOr , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalBoolOr }, + + { PEX_LeftShift , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeUInt32, EvalSHL }, + { PEX_LeftShift , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalSHL }, + + { PEX_RightShift , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeUInt32, EvalSHR_S }, + { PEX_RightShift , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalSHR_U }, + + { PEX_LT , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalLTSInt32 }, + { PEX_LT , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalLTUInt32 }, + { PEX_LT , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalLTFloat64 }, + + { PEX_LTEQ , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalLTEQSInt32 }, + { PEX_LTEQ , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalLTEQUInt32 }, + { PEX_LTEQ , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalLTEQFloat64 }, + + { PEX_EQEQ , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalEQEQSInt32 }, + { PEX_EQEQ , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalEQEQUInt32 }, + { PEX_EQEQ , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalEQEQFloat64 }, + + { PEX_LTGTEQ , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalLTGTEQSInt32 }, + { PEX_LTGTEQ , (PType **)&TypeSInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalLTGTEQUInt32 }, + { PEX_LTGTEQ , (PType **)&TypeSInt32, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalLTGTEQFloat64 }, + }; + for (size_t i = 0; i < countof(BinaryOpInit); ++i) + { + ZCC_OpInfo[BinaryOpInit[i].Op].AddProto(*BinaryOpInit[i].Res, *BinaryOpInit[i].Ltype, *BinaryOpInit[i].Rtype, BinaryOpInit[i].EvalConst); + } +} + +static void IntToS32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + // Integers always fill out the full sized 32-bit field, so converting + // from a smaller sized integer to a 32-bit one is as simple as changing + // the type field. + expr->Type = TypeSInt32; +} + +static void S32toS8(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + expr->IntVal = ((expr->IntVal << 24) >> 24); + expr->Type = TypeSInt8; +} + +static void S32toS16(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + expr->IntVal = ((expr->IntVal << 16) >> 16); + expr->Type = TypeSInt16; +} + +static void S32toU8(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + expr->IntVal &= 0xFF; + expr->Type = TypeUInt8; +} + +static void S32toU16(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + expr->IntVal &= 0xFFFF; + expr->Type = TypeUInt16; +} + +static void S32toU32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + expr->Type = TypeUInt32; +} + +static void S32toD(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + expr->DoubleVal = expr->IntVal; + expr->Type = TypeFloat64; +} + +static void DtoS32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + expr->IntVal = (int)expr->DoubleVal; + expr->Type = TypeSInt32; +} + +static void U32toD(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + expr->DoubleVal = expr->UIntVal; + expr->Type = TypeFloat64; +} + +static void DtoU32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + expr->UIntVal = (unsigned int)expr->DoubleVal; + expr->Type = TypeUInt32; +} + +static void S32toS(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + char str[16]; + int len = mysnprintf(str, countof(str), "%i", expr->IntVal); + expr->StringVal = str_arena.Alloc(str, len); + expr->Type = TypeString; +} + +static void U32toS(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + char str[16]; + int len = mysnprintf(str, countof(str), "%u", expr->UIntVal); + expr->StringVal = str_arena.Alloc(str, len); + expr->Type = TypeString; +} + +static void DtoS(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + // Convert to a string with enough precision such that converting + // back to a double will not lose any data. + char str[64]; + int len = mysnprintf(str, countof(str), "%H", expr->DoubleVal); + expr->StringVal = str_arena.Alloc(str, len); + expr->Type = TypeString; +} + +//========================================================================== +// +// ZCC_InitConversions +// +//========================================================================== + +void ZCC_InitConversions() +{ + TypeUInt8->AddConversion(TypeSInt32, IntToS32); + TypeSInt8->AddConversion(TypeSInt32, IntToS32); + TypeUInt16->AddConversion(TypeSInt32, IntToS32); + TypeSInt16->AddConversion(TypeSInt32, IntToS32); + + TypeUInt32->AddConversion(TypeSInt32, IntToS32); + TypeUInt32->AddConversion(TypeFloat64, U32toD); + TypeUInt32->AddConversion(TypeString, U32toS); + + TypeSInt32->AddConversion(TypeUInt8, S32toU8); + TypeSInt32->AddConversion(TypeSInt8, S32toS8); + TypeSInt32->AddConversion(TypeSInt16, S32toS16); + TypeSInt32->AddConversion(TypeUInt16, S32toU16); + TypeSInt32->AddConversion(TypeUInt32, S32toU32); + TypeSInt32->AddConversion(TypeFloat64, S32toD); + TypeSInt32->AddConversion(TypeString, S32toS); + + TypeFloat64->AddConversion(TypeUInt32, DtoU32); + TypeFloat64->AddConversion(TypeSInt32, DtoS32); + TypeFloat64->AddConversion(TypeString, DtoS); +} diff --git a/src/zscript/zcc_exprlist.h b/src/zscript/zcc_exprlist.h new file mode 100644 index 000000000..02bb8095f --- /dev/null +++ b/src/zscript/zcc_exprlist.h @@ -0,0 +1,56 @@ +// Name n-ary +xx(Nil, 0) + +xx(ID, 0) +xx(Super, 0) +xx(Self, 0) +xx(ConstValue, 0) +xx(FuncCall, 0) +xx(ArrayAccess, 0) +xx(MemberAccess, 0) + +xx(PostInc, 1) +xx(PostDec, 1) + +xx(PreInc, 1) +xx(PreDec, 1) +xx(Negate, 1) +xx(AntiNegate, 1) +xx(BitNot, 1) +xx(BoolNot, 1) +xx(SizeOf, 1) +xx(AlignOf, 1) + +xx(Add, 2) +xx(Sub, 2) +xx(Mul, 2) +xx(Div, 2) +xx(Mod, 2) +xx(Pow, 2) +xx(CrossProduct, 2) +xx(DotProduct, 2) +xx(LeftShift, 2) +xx(RightShift, 2) +xx(Concat, 2) + +xx(LT, 2) +xx(LTEQ, 2) +xx(LTGTEQ, 2) +xx(Is, 2) + +xx(EQEQ, 2) +xx(APREQ, 2) + +xx(BitAnd, 2) +xx(BitOr, 2) +xx(BitXor, 2) +xx(BoolAnd, 2) +xx(BoolOr, 2) + +xx(Scope, 0) + +xx(Trinary, 2) + +xx(Cast, 1) + +#undef xx diff --git a/src/zscript/zcc_parser.cpp b/src/zscript/zcc_parser.cpp index 32127ed46..1e3591da0 100644 --- a/src/zscript/zcc_parser.cpp +++ b/src/zscript/zcc_parser.cpp @@ -5,8 +5,8 @@ #include "w_wad.h" #include "cmdlib.h" #include "m_alloc.h" -#include "memarena.h" #include "zcc_parser.h" +#include "zcc_compile.h" static FString ZCCTokenName(int terminal); @@ -106,6 +106,8 @@ static void InitTokenMap() TOKENDEF2(TK_Map, ZCC_MAP, NAME_map); TOKENDEF2(TK_Array, ZCC_ARRAY, NAME_array); TOKENDEF (TK_Void, ZCC_VOID); + TOKENDEF (TK_True, ZCC_TRUE); + TOKENDEF (TK_False, ZCC_FALSE); TOKENDEF ('[', ZCC_LBRACKET); TOKENDEF (']', ZCC_RBRACKET); TOKENDEF (TK_In, ZCC_IN); @@ -144,6 +146,9 @@ static void InitTokenMap() TOKENDEF (TK_UIntConst, ZCC_UINTCONST); TOKENDEF (TK_FloatConst, ZCC_FLOATCONST); TOKENDEF (TK_NonWhitespace, ZCC_NWS); + + ZCC_InitOperators(); + ZCC_InitConversions(); } #undef TOKENDEF #undef TOKENDEF2 @@ -249,16 +254,18 @@ static void DoParse(const char *filename) ZCCParse(parser, ZCC_EOF, value, &state); ZCCParse(parser, 0, value, &state); ZCCParseFree(parser, free); + + PSymbolTable symbols; + ZCCCompiler cc(state, NULL, symbols); + cc.Compile(); #ifdef _DEBUG if (f != NULL) { fclose(f); } -#endif FString ast = ZCC_PrintAST(state.TopNode); FString astfile = ExtractFileBase(filename, false); astfile << ".ast"; -#ifdef _DEBUG f = fopen(astfile, "w"); if (f != NULL) { diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index 50e75fd94..9e2cf6cb3 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -121,59 +121,8 @@ enum EZCCBuiltinType enum EZCCExprType { - PEX_Nil, - - PEX_ID, - PEX_Super, - PEX_Self, - PEX_ConstValue, - 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, +#define xx(a,z) PEX_##a, +#include "zcc_exprlist.h" PEX_COUNT_OF }; @@ -345,6 +294,7 @@ struct ZCC_ExprConstant : ZCC_Expression { FString *StringVal; int IntVal; + unsigned int UIntVal; double DoubleVal; }; }; @@ -491,8 +441,59 @@ struct ZCC_FuncDeclarator : ZCC_Declarator ZCC_Statement *Body; }; +typedef ZCC_ExprConstant *(*EvalConst1op)(ZCC_ExprConstant *); +typedef ZCC_ExprConstant *(*EvalConst2op)(ZCC_ExprConstant *, ZCC_ExprConstant *, FSharedStringArena &); + +struct ZCC_OpProto +{ + ZCC_OpProto *Next; + PType *ResType; + PType *Type1; + PType *Type2; + union + { + EvalConst1op EvalConst1; + EvalConst2op EvalConst2; + }; + + ZCC_OpProto(PType *res, PType *t1, PType *t2) + : ResType(res), Type1(t1), Type2(t2) {} +}; + +struct ZCC_OpInfoType +{ + BYTE Nary:2; // n-ary-ness of operator + + const char *OpName; + ZCC_OpProto *Protos; + + void AddProto(PType *res, PType *optype, EvalConst1op evalconst); + void AddProto(PType *res, PType *left, PType *right, EvalConst2op evalconst); + + ZCC_OpProto *FindBestProto(PType *optype, const PType::Conversion **route, int &numslots); + ZCC_OpProto *FindBestProto(PType *left, const PType::Conversion **route1, int &numslots, + PType *right, const PType::Conversion **route2, int &numslots2); +}; + +#define CONVERSION_ROUTE_SIZE 8 + FString ZCC_PrintAST(ZCC_TreeNode *root); +void ZCC_InitOperators(); + +extern ZCC_OpInfoType ZCC_OpInfo[PEX_COUNT_OF]; + +static inline bool IsUnaryOp(EZCCExprType op) +{ + assert((unsigned)op < (unsigned)PEX_COUNT_OF); + return ZCC_OpInfo[op].Nary == 1; +} +static inline bool IsBinaryOp(EZCCExprType op) +{ + assert((unsigned)op < (unsigned)PEX_COUNT_OF); + return ZCC_OpInfo[op].Nary == 2; +} + struct ZCC_AST { ZCC_AST() : TopNode(NULL) {} diff --git a/zdoom.vcproj b/zdoom.vcproj index 124e2b998..597535708 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -3717,6 +3717,26 @@ /> </FileConfiguration> </File> + <File + RelativePath=".\src\zscript\zcc_compile.cpp" + > + </File> + <File + RelativePath=".\src\zscript\zcc_compile.h" + > + </File> + <File + RelativePath=".\src\zscript\zcc_errors.h" + > + </File> + <File + RelativePath=".\src\zscript\zcc_expr.cpp" + > + </File> + <File + RelativePath=".\src\zscript\zcc_exprlist.h" + > + </File> <File RelativePath=".\src\zscript\zcc_parser.cpp" > From 76d2e8cfc4ff7b9653afe0f60e7392ef6bcfe28d Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 25 Oct 2013 21:12:28 -0500 Subject: [PATCH 177/232] Set node type when nil-ing an id node. - Nodes can't stay as type AST_ExprID if they don't also have the operation PEX_ID. --- src/zscript/zcc_compile.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zscript/zcc_compile.cpp b/src/zscript/zcc_compile.cpp index 86f2d3ea2..385db01e3 100644 --- a/src/zscript/zcc_compile.cpp +++ b/src/zscript/zcc_compile.cpp @@ -352,6 +352,7 @@ ZCC_Expression *ZCCCompiler::IdentifyIdentifier(ZCC_ExprID *idnode) // Identifier didn't refer to anything good, so type error it. idnode->Type = TypeError; idnode->Operation = PEX_Nil; + idnode->NodeType = AST_Expression; return idnode; } From 63846134877758ca0c1ba699d2e0674a4d7a0223 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 25 Oct 2013 22:01:18 -0500 Subject: [PATCH 178/232] Allow using constants in other constants before their definitions. - Something like this is now valid: const foo = bar + 10; const bar = 1000; --- src/zscript/zcc_compile.cpp | 96 ++++++++++++++++++++++++++++++++----- src/zscript/zcc_compile.h | 3 ++ src/zscript/zcc_errors.h | 2 + 3 files changed, 89 insertions(+), 12 deletions(-) diff --git a/src/zscript/zcc_compile.cpp b/src/zscript/zcc_compile.cpp index 385db01e3..61f96a90c 100644 --- a/src/zscript/zcc_compile.cpp +++ b/src/zscript/zcc_compile.cpp @@ -10,6 +10,8 @@ #include "v_text.h" #include "gdtoa.h" +#define DEFINING_CONST ((PSymbolConst *)(void *)1) + //========================================================================== // // ZCCCompiler Constructor @@ -27,12 +29,33 @@ ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols) { switch (node->NodeType) { - case AST_Class: Classes.Push(static_cast<ZCC_Class *>(node)); break; - case AST_Struct: Structs.Push(static_cast<ZCC_Struct *>(node)); break; + case AST_Class: +// if (AddNamedNode(static_cast<ZCC_Class *>(node)->ClassName, node)) + { + Classes.Push(static_cast<ZCC_Class *>(node)); + } + break; + + case AST_Struct: + if (AddNamedNode(static_cast<ZCC_Struct *>(node)->StructName, node)) + { + Structs.Push(static_cast<ZCC_Struct *>(node)); + } + break; + case AST_Enum: break; case AST_EnumTerminator:break; - case AST_ConstantDef: Constants.Push(static_cast<ZCC_ConstantDef *>(node)); break; - default: assert(0 && "Unhandled AST node type"); break; + + case AST_ConstantDef: + if (AddNamedNode(static_cast<ZCC_ConstantDef *>(node)->Name, node)) + { + Constants.Push(static_cast<ZCC_ConstantDef *>(node)); + } + break; + + default: + assert(0 && "Unhandled AST node type"); + break; } node = node->SiblingNext; } @@ -40,6 +63,31 @@ ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols) } } +//========================================================================== +// +// ZCCCompiler :: AddNamedNode +// +// Keeps track of definition nodes by their names. Ensures that all names +// in this scope are unique. +// +//========================================================================== + +bool ZCCCompiler::AddNamedNode(FName name, ZCC_TreeNode *node) +{ + ZCC_TreeNode **check = NamedNodes.CheckKey(name); + if (check != NULL && *check != NULL) + { + Message(node, ERR_symbol_redefinition, "Attempt to redefine '%s'", name.GetChars()); + Message(*check, ERR_original_definition, " Original definition is here"); + return false; + } + else + { + NamedNodes.Insert(name, node); + return true; + } +} + //========================================================================== // // ZCCCompiler :: Message @@ -104,11 +152,7 @@ void ZCCCompiler::CompileConstants() ZCC_ConstantDef *def = Constants[i]; if (def->Symbol == NULL) { - PSymbolConst *sym = CompileConstant(def); - if (NULL == Symbols.AddSymbol(sym)) - { - Message(Constants[i], ERR_symbol_redefinition, "Redefinition of symbol '%s'", FName(def->Name).GetChars()); - } + CompileConstant(def); } } } @@ -127,7 +171,7 @@ PSymbolConst *ZCCCompiler::CompileConstant(ZCC_ConstantDef *def) { assert(def->Symbol == NULL); - def->Symbol = (PSymbolConst *)(void *)1; // mark as being defined (avoid recursion) + def->Symbol = DEFINING_CONST; // avoid recursion ZCC_Expression *val = Simplify(def->Value); def->Value = val; PSymbolConst *sym = NULL; @@ -161,6 +205,8 @@ PSymbolConst *ZCCCompiler::CompileConstant(ZCC_ConstantDef *def) sym = new PSymbolConstNumeric(def->Name, TypeError, 0); } def->Symbol = sym; + PSymbol *addsym = Symbols.AddSymbol(sym); + assert(NULL != addsym && "Symbol was redefined (but we shouldn't have even had the chance to do so)"); return sym; } @@ -347,7 +393,28 @@ ZCC_Expression *ZCCCompiler::IdentifyIdentifier(ZCC_ExprID *idnode) } } else - { + { // Check nodes that haven't had symbols created for them yet. + ZCC_TreeNode **node = NamedNodes.CheckKey(idnode->Identifier); + if (node != NULL && *node != NULL) + { + if ((*node)->NodeType == AST_ConstantDef) + { + ZCC_ConstantDef *def = static_cast<ZCC_ConstantDef *>(*node); + PSymbolConst *sym = def->Symbol; + + if (sym == DEFINING_CONST) + { + Message(idnode, ERR_recursive_definition, "Definition of '%s' is infinitely recursive", FName(idnode->Identifier).GetChars()); + sym = NULL; + } + else + { + assert(sym == NULL); + sym = CompileConstant(def); + } + return NodeFromSymbolConst(sym, idnode); + } + } } // Identifier didn't refer to anything good, so type error it. idnode->Type = TypeError; @@ -368,7 +435,12 @@ ZCC_ExprConstant *ZCCCompiler::NodeFromSymbolConst(PSymbolConst *sym, ZCC_ExprID { ZCC_ExprConstant *val = static_cast<ZCC_ExprConstant *>(AST.InitNode(sizeof(*val), AST_ExprConstant, idnode)); val->Operation = PEX_ConstValue; - if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConstString))) + if (sym == NULL) + { + val->Type = TypeError; + val->IntVal = 0; + } + else if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConstString))) { val->StringVal = AST.Strings.Alloc(static_cast<PSymbolConstString *>(sym)->Str); val->Type = TypeString; diff --git a/src/zscript/zcc_compile.h b/src/zscript/zcc_compile.h index 78632e444..69311cdee 100644 --- a/src/zscript/zcc_compile.h +++ b/src/zscript/zcc_compile.h @@ -16,6 +16,9 @@ private: TArray<ZCC_ConstantDef *> Constants; TArray<ZCC_Struct *> Structs; TArray<ZCC_Class *> Classes; + TMap<FName, ZCC_TreeNode *> NamedNodes; + + bool AddNamedNode(FName name, ZCC_TreeNode *node); ZCC_Expression *Simplify(ZCC_Expression *root); ZCC_Expression *SimplifyUnary(ZCC_ExprUnary *unary); diff --git a/src/zscript/zcc_errors.h b/src/zscript/zcc_errors.h index bfb617b63..4b492d02b 100644 --- a/src/zscript/zcc_errors.h +++ b/src/zscript/zcc_errors.h @@ -5,4 +5,6 @@ enum EZCCError ERR_const_def_not_constant = 20000 | ZCCERR_ERROR, ERR_bad_const_def_type = 20001 | ZCCERR_ERROR, ERR_symbol_redefinition = 20002 | ZCCERR_ERROR, + ERR_original_definition = 20003 | ZCCERR_ERROR, + ERR_recursive_definition = 20004 | ZCCERR_ERROR, }; From 2b96db5facec12a199e3d1ec89cb610ca5019718 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 25 Oct 2013 22:20:22 -0500 Subject: [PATCH 179/232] Do not share constant 1 for enum autoincrements. - AST nodes cannot be shared, because type conversion changes them in place, and what's appropriate for one use is by no means appropriate for all uses. --- src/zscript/zcc-parse.lemon | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index ae31a1e09..8a8620a42 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -280,7 +280,6 @@ enum_def(X) ::= ENUM(T) IDENTIFIER(A) enum_type(B) LBRACE opt_enum_list(C) RBRAC if (C != NULL) { ZCC_ConstantDef *node = C, *prev = node; - ZCC_ExprConstant *one = NULL; if (node->Value == NULL) { @@ -308,11 +307,7 @@ enum_def(X) ::= ENUM(T) IDENTIFIER(A) enum_type(B) LBRACE opt_enum_list(C) RBRAC // Otherwise, create a new addition expression to add 1. else { - if (one == NULL) - { // Use a single 1 node for the right-hand side of the addition. - NEW_INTCONST_NODE(cval, TypeSInt32, 1, T); - one = cval; - } + NEW_INTCONST_NODE(one, TypeSInt32, 1, T); NEW_AST_NODE(ExprID, label, node); label->Operation = PEX_ID; label->Identifier = prev->Name; From 03c4244fd867c175b99f10116fa22aac04132a3e Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 29 Oct 2013 13:34:03 -0500 Subject: [PATCH 180/232] Accept only one identifier for class names. --- src/zscript/ast.cpp | 2 +- src/zscript/zcc-parse.lemon | 4 ++-- src/zscript/zcc_compile.cpp | 2 +- src/zscript/zcc_parser.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/zscript/ast.cpp b/src/zscript/ast.cpp index 77335fcde..7424e9aae 100644 --- a/src/zscript/ast.cpp +++ b/src/zscript/ast.cpp @@ -276,7 +276,7 @@ static void PrintClass(FLispString &out, ZCC_TreeNode *node) ZCC_Class *cnode = (ZCC_Class *)node; out.Break(); out.Open("class"); - PrintNodes(out, cnode->ClassName); + out.AddName(cnode->ClassName); PrintNodes(out, cnode->ParentName); PrintNodes(out, cnode->Replaces); out.AddHex(cnode->Flags); diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index 8a8620a42..d94eb582c 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -158,10 +158,10 @@ class_definition(X) ::= class_head(A) class_body(B). X = A; } -class_head(X) ::= CLASS(T) dottable_id(A) class_ancestry(B) class_flags(C). +class_head(X) ::= CLASS(T) IDENTIFIER(A) class_ancestry(B) class_flags(C). { NEW_AST_NODE(Class,head,T); - head->ClassName = A; + head->ClassName = A.Name(); head->ParentName = B; head->Flags = C.Flags; head->Replaces = C.Replaces; diff --git a/src/zscript/zcc_compile.cpp b/src/zscript/zcc_compile.cpp index 61f96a90c..ce02c8e82 100644 --- a/src/zscript/zcc_compile.cpp +++ b/src/zscript/zcc_compile.cpp @@ -30,7 +30,7 @@ ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols) switch (node->NodeType) { case AST_Class: -// if (AddNamedNode(static_cast<ZCC_Class *>(node)->ClassName, node)) + if (AddNamedNode(static_cast<ZCC_Class *>(node)->ClassName, node)) { Classes.Push(static_cast<ZCC_Class *>(node)); } diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index 9e2cf6cb3..03a42a436 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -175,7 +175,7 @@ struct ZCC_Identifier : ZCC_TreeNode struct ZCC_Class : ZCC_TreeNode { - ZCC_Identifier *ClassName; + ENamedName ClassName; ZCC_Identifier *ParentName; ZCC_Identifier *Replaces; VM_UWORD Flags; From b227a2f5084245cabb78237fad7d0bf24db82a0b Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 29 Oct 2013 13:51:25 -0500 Subject: [PATCH 181/232] Add the basic types to the global symbol table --- src/dobjtype.cpp | 26 ++++++++++++++++++++++++++ src/dobjtype.h | 15 +++++++++++++++ src/namedef.h | 10 +++++++++- src/thingdef/thingdef.cpp | 1 - src/thingdef/thingdef_exp.h | 1 - src/zscript/zcc_expr.cpp | 2 -- 6 files changed, 50 insertions(+), 5 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index aaa507c09..22e2f73c3 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -58,6 +58,7 @@ // PUBLIC DATA DEFINITIONS ------------------------------------------------- FTypeTable TypeTable; +PSymbolTable GlobalSymbols; TArray<PClass *> PClass::AllClasses; bool PClass::bShutdown; @@ -458,6 +459,7 @@ void PType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const void PType::StaticInit() { + // Set up TypeTable hash keys. RUNTIME_CLASS(PErrorType)->TypeTableType = RUNTIME_CLASS(PErrorType); RUNTIME_CLASS(PVoidType)->TypeTableType = RUNTIME_CLASS(PVoidType); RUNTIME_CLASS(PInt)->TypeTableType = RUNTIME_CLASS(PInt); @@ -481,6 +483,7 @@ void PType::StaticInit() RUNTIME_CLASS(PFixed)->TypeTableType = RUNTIME_CLASS(PFixed); RUNTIME_CLASS(PAngle)->TypeTableType = RUNTIME_CLASS(PAngle); + // Create types and add them type the type table. TypeTable.AddType(TypeError = new PErrorType); TypeTable.AddType(TypeVoid = new PVoidType); TypeTable.AddType(TypeSInt8 = new PInt(1, false)); @@ -499,6 +502,26 @@ void PType::StaticInit() TypeTable.AddType(TypeState = new PStatePointer); TypeTable.AddType(TypeFixed = new PFixed); TypeTable.AddType(TypeAngle = new PAngle); + + // Add types to the global symbol table. + GlobalSymbols.AddSymbol(new PSymbolType(NAME_sbyte, TypeSInt8)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_byte, TypeUInt8)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_short, TypeSInt16)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_ushort, TypeUInt16)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_int, TypeSInt32)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_uint, TypeUInt32)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_bool, TypeBool)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_float, TypeFloat64)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_double, TypeFloat64)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_float32, TypeFloat32)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_float64, TypeFloat64)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_string, TypeString)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_name, TypeName)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_sound, TypeSound)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_color, TypeColor)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_state, TypeState)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_fixed, TypeFixed)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_angle, TypeAngle)); } @@ -2454,6 +2477,9 @@ IMPLEMENT_ABSTRACT_CLASS(PSymbol); IMPLEMENT_CLASS(PSymbolConst); IMPLEMENT_CLASS(PSymbolConstNumeric); IMPLEMENT_CLASS(PSymbolConstString); +IMPLEMENT_POINTY_CLASS(PSymbolType) + DECLARE_POINTER(Type) +END_POINTERS IMPLEMENT_POINTY_CLASS(PSymbolVMFunction) DECLARE_POINTER(Function) END_POINTERS diff --git a/src/dobjtype.h b/src/dobjtype.h index b66f68340..e1e5df710 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -55,6 +55,19 @@ public: PSymbolVMFunction() : PSymbol(NAME_None) {} }; +// A symbol for a type ------------------------------------------------------ + +class PSymbolType : public PSymbol +{ + DECLARE_CLASS(PSymbolType, PSymbol); + HAS_OBJECT_POINTERS; +public: + class PType *Type; + + PSymbolType(FName name, class PType *ty) : PSymbol(name), Type(ty) {} + PSymbolType() : PSymbol(NAME_None) {} +}; + // A symbol table ----------------------------------------------------------- struct PSymbolTable @@ -89,6 +102,8 @@ private: friend class DObject; }; +extern PSymbolTable GlobalSymbols; + // Basic information shared by all types ------------------------------------ // Only one copy of a type is ever instantiated at one time. diff --git a/src/namedef.h b/src/namedef.h index 8f762125e..ed9f9183b 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -578,7 +578,7 @@ xx(DecoNameToClass) xx(DecoFindMultiNameState) xx(DecoFindSingleNameState) -// fallback names for ZScript parser +// basic type names xx(default) xx(sbyte) xx(byte) @@ -588,8 +588,16 @@ xx(int) xx(uint) xx(bool) xx(float) +xx(float32) +xx(float64) xx(double) xx(string) xx(vector) xx(map) xx(array) +xx(name) +xx(sound) +xx(color) +xx(state) +xx(fixed) +xx(angle) diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 049e017bc..8b93b7e54 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -74,7 +74,6 @@ void ParseDecorate (FScanner &sc); // STATIC FUNCTION PROTOTYPES -------------------------------------------- PClassActor *QuestItemClasses[31]; -PSymbolTable GlobalSymbols; //========================================================================== // diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 1b3e5d854..9be15cb37 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -50,7 +50,6 @@ #define SAFE_RESOLVE(p,c) RESOLVE(p,c); ABORT(p) class VMFunctionBuilder; -extern PSymbolTable GlobalSymbols; //========================================================================== // diff --git a/src/zscript/zcc_expr.cpp b/src/zscript/zcc_expr.cpp index 9d5f1e683..3f5aec298 100644 --- a/src/zscript/zcc_expr.cpp +++ b/src/zscript/zcc_expr.cpp @@ -10,8 +10,6 @@ #define luai_nummod(a,b) ((a) - floor((a)/(b))*(b)) -extern PSymbolTable GlobalSymbols; - ZCC_OpInfoType ZCC_OpInfo[PEX_COUNT_OF] = { #define xx(a,n) { n, #a, NULL }, From 82c22459dce17ae2f688ad654401d08668d87325 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 29 Oct 2013 13:53:54 -0500 Subject: [PATCH 182/232] Give all types a symbol table, not just structs and derivatives --- src/dobjtype.cpp | 18 +++++++++++++----- src/dobjtype.h | 4 +++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 22e2f73c3..b025cd032 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -214,6 +214,18 @@ PType::~PType() { } +//========================================================================== +// +// PType :: PropagateMark +// +//========================================================================== + +size_t PType::PropagateMark() +{ + size_t marked = Symbols.MarkSymbols(); + return marked + Super::PropagateMark(); +} + //========================================================================== // // PType :: AddConversion @@ -1639,12 +1651,8 @@ PField *PStruct::AddField(FName name, PType *type, DWORD flags) size_t PStruct::PropagateMark() { - size_t marked; - GC::MarkArray(Fields); - marked = Fields.Size() * sizeof(void*); - marked += Symbols.MarkSymbols(); - return marked + Super::PropagateMark(); + return Fields.Size() * sizeof(void*) + Super::PropagateMark(); } //========================================================================== diff --git a/src/dobjtype.h b/src/dobjtype.h index e1e5df710..402a90ffc 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -156,6 +156,7 @@ public: unsigned int Size; // this type's size unsigned int Align; // this type's preferred alignment PType *HashNext; // next type in this type table + PSymbolTable Symbols; PType(); PType(unsigned int size, unsigned int align); @@ -191,6 +192,8 @@ public: // Get the type IDs used by IsMatch virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; + size_t PropagateMark(); + static void StaticInit(); private: @@ -530,7 +533,6 @@ public: PStruct(FName name, DObject *outer); TArray<PField *> Fields; - PSymbolTable Symbols; PField *AddField(FName name, PType *type, DWORD flags=0); From 61b419c18767a09ea2f23df027163c1609b823c6 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 29 Oct 2013 21:18:30 -0500 Subject: [PATCH 183/232] Remove duplicated names from namedef.h - Added an assertion in FName::NameManager::InitBuckets() that makes these errors easier to spot in the future. --- src/name.cpp | 1 + src/namedef.h | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/name.cpp b/src/name.cpp index 36cce2595..07482ec52 100644 --- a/src/name.cpp +++ b/src/name.cpp @@ -182,6 +182,7 @@ void FName::NameManager::InitBuckets () // Register built-in names. 'None' must be name 0. for (size_t i = 0; i < countof(PredefinedNames); ++i) { + assert(NULL == FindName(PredefinedNames[i], true) && "Predefined name already inserted"); FindName (PredefinedNames[i], false); } } diff --git a/src/namedef.h b/src/namedef.h index ed9f9183b..9d8496280 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -595,9 +595,6 @@ xx(string) xx(vector) xx(map) xx(array) -xx(name) xx(sound) -xx(color) xx(state) xx(fixed) -xx(angle) From 6c7788d2adb1d8d42b81b1a12a02bcb3ae1eebee Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 29 Oct 2013 21:27:22 -0500 Subject: [PATCH 184/232] Make global symbols survive GC runs - The global symbol table was never marked by the GC, so anything pointed only by it was fair game to disappear. - Don't clear the global symbol table during DECORATE parsing. Junk in there should be considered constant after initialization. --- src/dobjgc.cpp | 2 ++ src/thingdef/thingdef.cpp | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index da3d28ac1..51b98eee4 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -370,6 +370,8 @@ static void MarkRoot() { Mark(PClass::AllClasses[i]); } + // Mark global symbols + GlobalSymbols.MarkSymbols(); // Mark bot stuff. Mark(bglobal.firstthing); Mark(bglobal.body1); diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 8b93b7e54..0a02e2763 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -425,7 +425,6 @@ void LoadActors () timer.Reset(); timer.Clock(); ActorDamageFuncs.Clear(); - GlobalSymbols.ReleaseSymbols(); FScriptPosition::ResetErrorCounter(); InitThingdef(); lastlump = 0; From e696fff0be8006c169e19bcc0a0539a54aa1b5ee Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 29 Oct 2013 21:51:15 -0500 Subject: [PATCH 185/232] Capitalize some names that weren't before. - Since this caused several duplicate names to creep in, try to be more consistant abount name capitalization. --- src/dobjtype.cpp | 36 ++++++++++++++++++------------------ src/namedef.h | 38 +++++++++++++++++++------------------- src/zscript/zcc_parser.cpp | 28 ++++++++++++++-------------- 3 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index b025cd032..76ac79095 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -516,24 +516,24 @@ void PType::StaticInit() TypeTable.AddType(TypeAngle = new PAngle); // Add types to the global symbol table. - GlobalSymbols.AddSymbol(new PSymbolType(NAME_sbyte, TypeSInt8)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_byte, TypeUInt8)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_short, TypeSInt16)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_ushort, TypeUInt16)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_int, TypeSInt32)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_uint, TypeUInt32)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_bool, TypeBool)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_float, TypeFloat64)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_double, TypeFloat64)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_float32, TypeFloat32)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_float64, TypeFloat64)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_string, TypeString)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_name, TypeName)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_sound, TypeSound)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_color, TypeColor)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_state, TypeState)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_fixed, TypeFixed)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_angle, TypeAngle)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_sByte, TypeSInt8)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Byte, TypeUInt8)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Short, TypeSInt16)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_uShort, TypeUInt16)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Int, TypeSInt32)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_uInt, TypeUInt32)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Bool, TypeBool)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Float, TypeFloat64)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Double, TypeFloat64)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Float32, TypeFloat32)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Float64, TypeFloat64)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_String, TypeString)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Name, TypeName)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Sound, TypeSound)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Color, TypeColor)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_State, TypeState)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Fixed, TypeFixed)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Angle, TypeAngle)); } diff --git a/src/namedef.h b/src/namedef.h index 9d8496280..fb85502bf 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -579,22 +579,22 @@ xx(DecoFindMultiNameState) xx(DecoFindSingleNameState) // basic type names -xx(default) -xx(sbyte) -xx(byte) -xx(short) -xx(ushort) -xx(int) -xx(uint) -xx(bool) -xx(float) -xx(float32) -xx(float64) -xx(double) -xx(string) -xx(vector) -xx(map) -xx(array) -xx(sound) -xx(state) -xx(fixed) +xx(Default) +xx(sByte) +xx(Byte) +xx(Short) +xx(uShort) +xx(Int) +xx(uInt) +xx(Bool) +xx(Float) +xx(Float32) +xx(Float64) +xx(Double) +xx(String) +xx(Vector) +xx(Map) +xx(Array) +xx(Sound) +xx(State) +xx(Fixed) diff --git a/src/zscript/zcc_parser.cpp b/src/zscript/zcc_parser.cpp index 1e3591da0..8a9ea4567 100644 --- a/src/zscript/zcc_parser.cpp +++ b/src/zscript/zcc_parser.cpp @@ -91,20 +91,20 @@ static void InitTokenMap() TOKENDEF ('}', ZCC_RBRACE); TOKENDEF (TK_Struct, ZCC_STRUCT); TOKENDEF (TK_Enum, ZCC_ENUM); - TOKENDEF2(TK_SByte, ZCC_SBYTE, NAME_sbyte); - TOKENDEF2(TK_Byte, ZCC_BYTE, NAME_byte); - TOKENDEF2(TK_Short, ZCC_SHORT, NAME_short); - TOKENDEF2(TK_UShort, ZCC_USHORT, NAME_ushort); - TOKENDEF2(TK_Int, ZCC_INT, NAME_int); - TOKENDEF2(TK_UInt, ZCC_UINT, NAME_uint); - TOKENDEF2(TK_Bool, ZCC_BOOL, NAME_bool); - TOKENDEF2(TK_Float, ZCC_FLOAT, NAME_float); - TOKENDEF2(TK_Double, ZCC_DOUBLE, NAME_double); - TOKENDEF2(TK_String, ZCC_STRING, NAME_string); - TOKENDEF2(TK_Vector, ZCC_VECTOR, NAME_vector); + TOKENDEF2(TK_SByte, ZCC_SBYTE, NAME_sByte); + TOKENDEF2(TK_Byte, ZCC_BYTE, NAME_Byte); + TOKENDEF2(TK_Short, ZCC_SHORT, NAME_Short); + TOKENDEF2(TK_UShort, ZCC_USHORT, NAME_uShort); + TOKENDEF2(TK_Int, ZCC_INT, NAME_Int); + TOKENDEF2(TK_UInt, ZCC_UINT, NAME_uInt); + TOKENDEF2(TK_Bool, ZCC_BOOL, NAME_Bool); + TOKENDEF2(TK_Float, ZCC_FLOAT, NAME_Float); + TOKENDEF2(TK_Double, ZCC_DOUBLE, NAME_Double); + TOKENDEF2(TK_String, ZCC_STRING, NAME_String); + TOKENDEF2(TK_Vector, ZCC_VECTOR, NAME_Vector); TOKENDEF2(TK_Name, ZCC_NAME, NAME_Name); - TOKENDEF2(TK_Map, ZCC_MAP, NAME_map); - TOKENDEF2(TK_Array, ZCC_ARRAY, NAME_array); + TOKENDEF2(TK_Map, ZCC_MAP, NAME_Map); + TOKENDEF2(TK_Array, ZCC_ARRAY, NAME_Array); TOKENDEF (TK_Void, ZCC_VOID); TOKENDEF (TK_True, ZCC_TRUE); TOKENDEF (TK_False, ZCC_FALSE); @@ -130,7 +130,7 @@ static void InitTokenMap() TOKENDEF (TK_Else, ZCC_ELSE); TOKENDEF (TK_Switch, ZCC_SWITCH); TOKENDEF (TK_Case, ZCC_CASE); - TOKENDEF2(TK_Default, ZCC_DEFAULT, NAME_default); + TOKENDEF2(TK_Default, ZCC_DEFAULT, NAME_Default); TOKENDEF (TK_Const, ZCC_CONST); TOKENDEF (TK_Stop, ZCC_STOP); TOKENDEF (TK_Wait, ZCC_WAIT); From fe21ceec56728232a7b33f77fdb3601a1dcaddf6 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 29 Oct 2013 21:52:28 -0500 Subject: [PATCH 186/232] Add a constructor to PSymbolTable that takes a parent table as input --- src/dobjtype.cpp | 5 +++++ src/dobjtype.h | 1 + src/zscript/zcc_parser.cpp | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 76ac79095..161dc74e3 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2507,6 +2507,11 @@ PSymbolTable::PSymbolTable() { } +PSymbolTable::PSymbolTable(PSymbolTable *parent) +: ParentSymbolTable(parent) +{ +} + PSymbolTable::~PSymbolTable () { ReleaseSymbols(); diff --git a/src/dobjtype.h b/src/dobjtype.h index 402a90ffc..98f1187b9 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -73,6 +73,7 @@ public: struct PSymbolTable { PSymbolTable(); + PSymbolTable(PSymbolTable *parent); ~PSymbolTable(); size_t MarkSymbols(); diff --git a/src/zscript/zcc_parser.cpp b/src/zscript/zcc_parser.cpp index 8a9ea4567..b79de0f62 100644 --- a/src/zscript/zcc_parser.cpp +++ b/src/zscript/zcc_parser.cpp @@ -255,7 +255,7 @@ static void DoParse(const char *filename) ZCCParse(parser, 0, value, &state); ZCCParseFree(parser, free); - PSymbolTable symbols; + PSymbolTable symbols(&GlobalSymbols); ZCCCompiler cc(state, NULL, symbols); cc.Compile(); #ifdef _DEBUG From e7616ec0bd66f37ace2cb851eae8bdbcf0dd7600 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 29 Oct 2013 21:53:58 -0500 Subject: [PATCH 187/232] Add D-style properties to the numeric types - This is stuff like min and max for integral types and infinity and nan for floating point types. --- src/dobjtype.cpp | 132 ++++++++++++++++++++++++++++++++++++++++++++++- src/dobjtype.h | 19 ++++++- src/namedef.h | 14 +++++ 3 files changed, 162 insertions(+), 3 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 161dc74e3..60b46a541 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -34,6 +34,9 @@ // HEADER FILES ------------------------------------------------------------ +#include <float.h> +#include <limits> + #include "dobject.h" #include "i_system.h" #include "actor.h" @@ -609,8 +612,10 @@ IMPLEMENT_CLASS(PInt) //========================================================================== PInt::PInt() -: PBasicType(4, 4) +: PBasicType(4, 4), Unsigned(false) { + Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Min, this, -0x7FFFFFFF - 1)); + Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Max, this, 0x7FFFFFFF)); } //========================================================================== @@ -622,6 +627,18 @@ PInt::PInt() PInt::PInt(unsigned int size, bool unsign) : PBasicType(size, size), Unsigned(unsign) { + if (!unsign) + { + int maxval = (1 << ((8 * size) - 1)) - 1; + int minval = -maxval - 1; + Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Min, this, minval)); + Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Max, this, maxval)); + } + else + { + Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Min, this, 0u)); + Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Max, this, (1u << (8 * size)) - 1)); + } } //========================================================================== @@ -756,6 +773,21 @@ int PInt::GetRegType() const IMPLEMENT_CLASS(PBool) +//========================================================================== +// +// PBool Default Constructor +// +//========================================================================== + +PBool::PBool() +: PInt(sizeof(bool), true) +{ + // Override the default max set by PInt's constructor + PSymbolConstNumeric *maxsym = static_cast<PSymbolConstNumeric *>(Symbols.FindSymbol(NAME_Max, false)); + assert(maxsym != NULL && maxsym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric))); + maxsym->Value = 1; +} + /* PFloat *****************************************************************/ IMPLEMENT_CLASS(PFloat) @@ -767,8 +799,9 @@ IMPLEMENT_CLASS(PFloat) //========================================================================== PFloat::PFloat() -: PBasicType(4, 4) +: PBasicType(8, 8) { + SetDoubleSymbols(); } //========================================================================== @@ -780,6 +813,101 @@ PFloat::PFloat() PFloat::PFloat(unsigned int size) : PBasicType(size, size) { + if (size == 8) + { + SetDoubleSymbols(); + } + else + { + assert(size == 4); + SetSingleSymbols(); + } +} + +//========================================================================== +// +// PFloat :: SetDoubleSymbols +// +// Setup constant values for 64-bit floats. +// +//========================================================================== + +void PFloat::SetDoubleSymbols() +{ + static const SymbolInitF symf[] = + { + { NAME_Min_Normal, DBL_MIN }, + { NAME_Max, DBL_MAX }, + { NAME_Epsilon, DBL_EPSILON }, + { NAME_NaN, std::numeric_limits<double>::quiet_NaN() }, + { NAME_Infinity, std::numeric_limits<double>::infinity() }, + { NAME_Min_Denormal, std::numeric_limits<double>::denorm_min() } + }; + static const SymbolInitI symi[] = + { + { NAME_Dig, DBL_DIG }, + { NAME_Min_Exp, DBL_MIN_EXP }, + { NAME_Max_Exp, DBL_MAX_EXP }, + { NAME_Mant_Dig, DBL_MANT_DIG }, + { NAME_Min_10_Exp, DBL_MIN_10_EXP }, + { NAME_Max_10_Exp, DBL_MAX_10_EXP } + }; + SetSymbols(symf, countof(symf)); + SetSymbols(symi, countof(symi)); +} + +//========================================================================== +// +// PFloat :: SetSingleSymbols +// +// Setup constant values for 32-bit floats. +// +//========================================================================== + +void PFloat::SetSingleSymbols() +{ + static const SymbolInitF symf[] = + { + { NAME_Min_Normal, FLT_MIN }, + { NAME_Max, FLT_MAX }, + { NAME_Epsilon, FLT_EPSILON }, + { NAME_NaN, std::numeric_limits<float>::quiet_NaN() }, + { NAME_Infinity, std::numeric_limits<float>::infinity() }, + { NAME_Min_Denormal, std::numeric_limits<float>::denorm_min() } + }; + static const SymbolInitI symi[] = + { + { NAME_Dig, FLT_DIG }, + { NAME_Min_Exp, FLT_MIN_EXP }, + { NAME_Max_Exp, FLT_MAX_EXP }, + { NAME_Mant_Dig, FLT_MANT_DIG }, + { NAME_Min_10_Exp, FLT_MIN_10_EXP }, + { NAME_Max_10_Exp, FLT_MAX_10_EXP } + }; + SetSymbols(symf, countof(symf)); + SetSymbols(symi, countof(symi)); +} + +//========================================================================== +// +// PFloat :: SetSymbols +// +//========================================================================== + +void PFloat::SetSymbols(const PFloat::SymbolInitF *sym, size_t count) +{ + for (size_t i = 0; i < count; ++i) + { + Symbols.AddSymbol(new PSymbolConstNumeric(sym[i].Name, this, sym[i].Value)); + } +} + +void PFloat::SetSymbols(const PFloat::SymbolInitI *sym, size_t count) +{ + for (size_t i = 0; i < count; ++i) + { + Symbols.AddSymbol(new PSymbolConstNumeric(sym[i].Name, this, sym[i].Value)); + } } //========================================================================== diff --git a/src/dobjtype.h b/src/dobjtype.h index 98f1187b9..0463eee0b 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -315,7 +315,7 @@ class PBool : public PInt { DECLARE_CLASS(PBool, PInt); public: - PBool() : PInt(sizeof(bool), true) {} + PBool(); }; class PFloat : public PBasicType @@ -331,6 +331,22 @@ public: virtual int GetRegType() const; protected: PFloat(); +private: + struct SymbolInitF + { + ENamedName Name; + double Value; + }; + struct SymbolInitI + { + ENamedName Name; + int Value; + }; + + void SetSingleSymbols(); + void SetDoubleSymbols(); + void SetSymbols(const SymbolInitF *syminit, size_t count); + void SetSymbols(const SymbolInitI *syminit, size_t count); }; class PString : public PBasicType @@ -767,6 +783,7 @@ public: PSymbolConstNumeric(FName name, PType *type=NULL) : PSymbolConst(name, type) {} PSymbolConstNumeric(FName name, PType *type, int val) : PSymbolConst(name, type), Value(val) {} + PSymbolConstNumeric(FName name, PType *type, unsigned int val) : PSymbolConst(name, type), Value((int)val) {} PSymbolConstNumeric(FName name, PType *type, double val) : PSymbolConst(name, type), Float(val) {} PSymbolConstNumeric() {} }; diff --git a/src/namedef.h b/src/namedef.h index fb85502bf..53c2a9327 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -598,3 +598,17 @@ xx(Array) xx(Sound) xx(State) xx(Fixed) + +xx(Min) +xx(Max) +xx(Min_Normal) +xx(Min_Denormal) +xx(Epsilon) +xx(NaN) +xx(Infinity) +xx(Dig) +xx(Min_Exp) +xx(Max_Exp) +xx(Mant_Dig) +xx(Min_10_Exp) +xx(Max_10_Exp) From 39d7fa0605d7063e2f34afc77e1b0ce26d13ec87 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Tue, 29 Oct 2013 21:55:32 -0500 Subject: [PATCH 188/232] Allow access to the numeric properties. - Identifiers can now evaluate to type references. - The dot operator can now find symbols in type references. --- src/zscript/ast.cpp | 20 +++++++++ src/zscript/zcc_compile.cpp | 83 +++++++++++++++++++++++++++++++++++-- src/zscript/zcc_compile.h | 5 ++- src/zscript/zcc_errors.h | 2 + src/zscript/zcc_exprlist.h | 1 + src/zscript/zcc_parser.h | 6 +++ 6 files changed, 112 insertions(+), 5 deletions(-) diff --git a/src/zscript/ast.cpp b/src/zscript/ast.cpp index 7424e9aae..bba089a30 100644 --- a/src/zscript/ast.cpp +++ b/src/zscript/ast.cpp @@ -471,6 +471,25 @@ static void PrintExprID(FLispString &out, ZCC_TreeNode *node) out.Close(); } +static void PrintExprTypeRef(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_ExprTypeRef *enode = (ZCC_ExprTypeRef *)node; + assert(enode->Operation == PEX_TypeRef); + out.Open("expr-type-ref"); + if (enode->RefType == TypeSInt8) { out.Add("sint8"); } + else if (enode->RefType == TypeUInt8) { out.Add("uint8"); } + else if (enode->RefType == TypeSInt16) { out.Add("sint16"); } + else if (enode->RefType == TypeSInt32) { out.Add("sint32"); } + else if (enode->RefType == TypeFloat32) { out.Add("float32"); } + else if (enode->RefType == TypeFloat64) { out.Add("float64"); } + else if (enode->RefType == TypeString) { out.Add("string"); } + else if (enode->RefType == TypeName) { out.Add("name"); } + else if (enode->RefType == TypeColor) { out.Add("color"); } + else if (enode->RefType == TypeSound) { out.Add("sound"); } + else { out.Add("other"); } + out.Close(); +} + static void PrintExprConstant(FLispString &out, ZCC_TreeNode *node) { ZCC_ExprConstant *enode = (ZCC_ExprConstant *)node; @@ -767,6 +786,7 @@ void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode * PrintClassType, PrintExpression, PrintExprID, + PrintExprTypeRef, PrintExprConstant, PrintExprFuncCall, PrintExprMemberAccess, diff --git a/src/zscript/zcc_compile.cpp b/src/zscript/zcc_compile.cpp index ce02c8e82..b6ff67a47 100644 --- a/src/zscript/zcc_compile.cpp +++ b/src/zscript/zcc_compile.cpp @@ -230,6 +230,10 @@ ZCC_Expression *ZCCCompiler::Simplify(ZCC_Expression *root) { return IdentifyIdentifier(static_cast<ZCC_ExprID *>(root)); } + else if (root->Operation == PEX_MemberAccess) + { + return SimplifyMemberAccess(static_cast<ZCC_ExprMemberAccess *>(root)); + } else if (IsUnaryOp(root->Operation)) { return SimplifyUnary(static_cast<ZCC_ExprUnary *>(root)); @@ -286,6 +290,40 @@ ZCC_Expression *ZCCCompiler::SimplifyBinary(ZCC_ExprBinary *binary) return binary; } +//========================================================================== +// +// ZCCCompiler :: SimplifyMemberAccess +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::SimplifyMemberAccess(ZCC_ExprMemberAccess *dotop) +{ + dotop->Left = Simplify(dotop->Left); + + if (dotop->Left->Operation == PEX_TypeRef) + { // Type refs can be evaluated now. + PType *ref = static_cast<ZCC_ExprTypeRef *>(dotop->Left)->RefType; + PSymbol *sym = ref->Symbols.FindSymbol(dotop->Right, true); + if (sym == NULL) + { + Message(dotop, ERR_not_a_member, "'%s' is not a valid member", FName(dotop->Right).GetChars()); + } + else + { + ZCC_Expression *expr = NodeFromSymbol(sym, dotop); + if (expr == NULL) + { + Message(dotop, ERR_bad_symbol, "Unhandled symbol type encountered"); + } + else + { + return expr; + } + } + } + return dotop; +} + //========================================================================== // // ZCCCompiler :: PromoteUnary @@ -387,9 +425,10 @@ ZCC_Expression *ZCCCompiler::IdentifyIdentifier(ZCC_ExprID *idnode) PSymbol *sym; if (NULL != (sym = Symbols.FindSymbol(idnode->Identifier, true))) { - if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) + ZCC_Expression *node = NodeFromSymbol(sym, idnode); + if (node != NULL) { - return NodeFromSymbolConst(static_cast<PSymbolConst *>(sym), idnode); + return node; } } else @@ -425,13 +464,32 @@ ZCC_Expression *ZCCCompiler::IdentifyIdentifier(ZCC_ExprID *idnode) //========================================================================== // -// ZCCCompiler :: NodeFromSymoblConst +// ZCCCompiler :: NodeFromSymbol +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::NodeFromSymbol(PSymbol *sym, ZCC_Expression *source) +{ + if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) + { + return NodeFromSymbolConst(static_cast<PSymbolConst *>(sym), source); + } + else if (sym->IsKindOf(RUNTIME_CLASS(PSymbolType))) + { + return NodeFromSymbolType(static_cast<PSymbolType *>(sym), source); + } + return NULL; +} + +//========================================================================== +// +// ZCCCompiler :: NodeFromSymbolConst // // Returns a new AST constant node with the symbol's content. // //========================================================================== -ZCC_ExprConstant *ZCCCompiler::NodeFromSymbolConst(PSymbolConst *sym, ZCC_ExprID *idnode) +ZCC_ExprConstant *ZCCCompiler::NodeFromSymbolConst(PSymbolConst *sym, ZCC_Expression *idnode) { ZCC_ExprConstant *val = static_cast<ZCC_ExprConstant *>(AST.InitNode(sizeof(*val), AST_ExprConstant, idnode)); val->Operation = PEX_ConstValue; @@ -464,3 +522,20 @@ ZCC_ExprConstant *ZCCCompiler::NodeFromSymbolConst(PSymbolConst *sym, ZCC_ExprID } return val; } + +//========================================================================== +// +// ZCCCompiler :: NodeFromSymbolType +// +// Returns a new AST type ref node with the symbol's content. +// +//========================================================================== + +ZCC_ExprTypeRef *ZCCCompiler::NodeFromSymbolType(PSymbolType *sym, ZCC_Expression *idnode) +{ + ZCC_ExprTypeRef *ref = static_cast<ZCC_ExprTypeRef *>(AST.InitNode(sizeof(*ref), AST_ExprTypeRef, idnode)); + ref->Operation = PEX_TypeRef; + ref->RefType = sym->Type; + ref->Type = NewClassPointer(RUNTIME_CLASS(PType)); + return ref; +} diff --git a/src/zscript/zcc_compile.h b/src/zscript/zcc_compile.h index 69311cdee..a5029ad93 100644 --- a/src/zscript/zcc_compile.h +++ b/src/zscript/zcc_compile.h @@ -23,6 +23,7 @@ private: ZCC_Expression *Simplify(ZCC_Expression *root); ZCC_Expression *SimplifyUnary(ZCC_ExprUnary *unary); ZCC_Expression *SimplifyBinary(ZCC_ExprBinary *binary); + ZCC_Expression *SimplifyMemberAccess(ZCC_ExprMemberAccess *dotop); ZCC_OpProto *PromoteUnary(EZCCExprType op, ZCC_Expression *&expr); ZCC_OpProto *PromoteBinary(EZCCExprType op, ZCC_Expression *&left, ZCC_Expression *&right); @@ -35,7 +36,9 @@ private: ZCC_Expression *AddCastNode(PType *type, ZCC_Expression *expr); ZCC_Expression *IdentifyIdentifier(ZCC_ExprID *idnode); - ZCC_ExprConstant *NodeFromSymbolConst(PSymbolConst *sym, ZCC_ExprID *idnode); + ZCC_Expression *NodeFromSymbol(PSymbol *sym, ZCC_Expression *source); + ZCC_ExprConstant *NodeFromSymbolConst(PSymbolConst *sym, ZCC_Expression *idnode); + ZCC_ExprTypeRef *NodeFromSymbolType(PSymbolType *sym, ZCC_Expression *idnode); void Message(ZCC_TreeNode *node, EZCCError errnum, const char *msg, ...); diff --git a/src/zscript/zcc_errors.h b/src/zscript/zcc_errors.h index 4b492d02b..7deb5737e 100644 --- a/src/zscript/zcc_errors.h +++ b/src/zscript/zcc_errors.h @@ -7,4 +7,6 @@ enum EZCCError ERR_symbol_redefinition = 20002 | ZCCERR_ERROR, ERR_original_definition = 20003 | ZCCERR_ERROR, ERR_recursive_definition = 20004 | ZCCERR_ERROR, + ERR_not_a_member = 20005 | ZCCERR_ERROR, + ERR_bad_symbol = 20006 | ZCCERR_ERROR, }; diff --git a/src/zscript/zcc_exprlist.h b/src/zscript/zcc_exprlist.h index 02bb8095f..cbe78ef09 100644 --- a/src/zscript/zcc_exprlist.h +++ b/src/zscript/zcc_exprlist.h @@ -8,6 +8,7 @@ xx(ConstValue, 0) xx(FuncCall, 0) xx(ArrayAccess, 0) xx(MemberAccess, 0) +xx(TypeRef, 0) xx(PostInc, 1) xx(PostDec, 1) diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index 03a42a436..47213b549 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -67,6 +67,7 @@ enum EZCCTreeNodeType AST_ClassType, AST_Expression, AST_ExprID, + AST_ExprTypeRef, AST_ExprConstant, AST_ExprFuncCall, AST_ExprMemberAccess, @@ -288,6 +289,11 @@ struct ZCC_ExprID : ZCC_Expression ENamedName Identifier; }; +struct ZCC_ExprTypeRef : ZCC_Expression +{ + PType *RefType; +}; + struct ZCC_ExprConstant : ZCC_Expression { union From 2adf5782b90933c6a921f9d8939f0e38c5a61893 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 30 Oct 2013 20:52:46 -0500 Subject: [PATCH 189/232] Return propertype conversion routes larger than 1 - Fixed: PType::FindConversion() gave all but the source type a distance of 0, so it only ever returned just one step of a route that requires more than one step. --- src/dobjtype.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 60b46a541..c601e1f55 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -291,7 +291,7 @@ int PType::FindConversion(PType *target, const PType::Conversion **slots, int nu PType *succ = t->Conversions[i].TargetType; if (!visited.Check(succ)) { - succ->MarkPred(t, i, Distance + 1); + succ->MarkPred(t, i, t->Distance + 1); visited.Insert(succ); queue.Push(succ); } From 16fc9be41124d8207e121aeaa4ad10145750c52e Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Wed, 30 Oct 2013 20:53:02 -0500 Subject: [PATCH 190/232] Interpret function calls to type refs as type casts --- src/zscript/zcc_compile.cpp | 80 ++++++++++++++++++++++++++++++++----- src/zscript/zcc_compile.h | 1 + src/zscript/zcc_errors.h | 2 + src/zscript/zcc_parser.h | 8 ++++ 4 files changed, 81 insertions(+), 10 deletions(-) diff --git a/src/zscript/zcc_compile.cpp b/src/zscript/zcc_compile.cpp index b6ff67a47..b95bc33b7 100644 --- a/src/zscript/zcc_compile.cpp +++ b/src/zscript/zcc_compile.cpp @@ -226,7 +226,15 @@ PSymbolConst *ZCCCompiler::CompileConstant(ZCC_ConstantDef *def) ZCC_Expression *ZCCCompiler::Simplify(ZCC_Expression *root) { - if (root->Operation == PEX_ID) + if (IsUnaryOp(root->Operation)) + { + return SimplifyUnary(static_cast<ZCC_ExprUnary *>(root)); + } + else if (IsBinaryOp(root->Operation)) + { + return SimplifyBinary(static_cast<ZCC_ExprBinary *>(root)); + } + else if (root->Operation == PEX_ID) { return IdentifyIdentifier(static_cast<ZCC_ExprID *>(root)); } @@ -234,13 +242,9 @@ ZCC_Expression *ZCCCompiler::Simplify(ZCC_Expression *root) { return SimplifyMemberAccess(static_cast<ZCC_ExprMemberAccess *>(root)); } - else if (IsUnaryOp(root->Operation)) + else if (root->Operation == PEX_FuncCall) { - return SimplifyUnary(static_cast<ZCC_ExprUnary *>(root)); - } - else if (IsBinaryOp(root->Operation)) - { - return SimplifyBinary(static_cast<ZCC_ExprBinary *>(root)); + return SimplifyFunctionCall(static_cast<ZCC_ExprFuncCall *>(root)); } return root; } @@ -324,6 +328,64 @@ ZCC_Expression *ZCCCompiler::SimplifyMemberAccess(ZCC_ExprMemberAccess *dotop) return dotop; } +//========================================================================== +// +// ZCCCompiler :: SimplifyFunctionCall +// +// This may replace a function call with cast(s), since they look like the +// same thing to the parser. +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::SimplifyFunctionCall(ZCC_ExprFuncCall *callop) +{ + ZCC_FuncParm *parm; + int parmcount = 0; + + callop->Function = Simplify(callop->Function); + parm = callop->Parameters; + if (parm != NULL) + { + do + { + parmcount++; + assert(parm->NodeType == AST_FuncParm); + parm->Value = Simplify(parm->Value); + parm = static_cast<ZCC_FuncParm *>(parm->SiblingNext); + } + while (parm != callop->Parameters); + } + // If the left side is a type ref, then this is actually a cast + // and not a function call. + if (callop->Function->Operation == PEX_TypeRef) + { + if (parmcount != 1) + { + Message(callop, ERR_cast_needs_1_parm, "Type cast requires one parameter"); + callop->ToErrorNode(); + } + else + { + PType *dest = static_cast<ZCC_ExprTypeRef *>(callop->Function)->RefType; + const PType::Conversion *route[CONVERSION_ROUTE_SIZE]; + int routelen = parm->Value->Type->FindConversion(dest, route, countof(route)); + if (routelen < 0) + { + // FIXME: Need real type names + Message(callop, ERR_cast_not_possible, "Cannot convert type 1 to type 2"); + callop->ToErrorNode(); + } + else + { + ZCC_Expression *val = ApplyConversion(parm->Value, route, routelen); + assert(val->Type == dest); + return val; + } + } + } + return callop; +} + //========================================================================== // // ZCCCompiler :: PromoteUnary @@ -456,9 +518,7 @@ ZCC_Expression *ZCCCompiler::IdentifyIdentifier(ZCC_ExprID *idnode) } } // Identifier didn't refer to anything good, so type error it. - idnode->Type = TypeError; - idnode->Operation = PEX_Nil; - idnode->NodeType = AST_Expression; + idnode->ToErrorNode(); return idnode; } diff --git a/src/zscript/zcc_compile.h b/src/zscript/zcc_compile.h index a5029ad93..c8933ff5f 100644 --- a/src/zscript/zcc_compile.h +++ b/src/zscript/zcc_compile.h @@ -24,6 +24,7 @@ private: ZCC_Expression *SimplifyUnary(ZCC_ExprUnary *unary); ZCC_Expression *SimplifyBinary(ZCC_ExprBinary *binary); ZCC_Expression *SimplifyMemberAccess(ZCC_ExprMemberAccess *dotop); + ZCC_Expression *SimplifyFunctionCall(ZCC_ExprFuncCall *callop); ZCC_OpProto *PromoteUnary(EZCCExprType op, ZCC_Expression *&expr); ZCC_OpProto *PromoteBinary(EZCCExprType op, ZCC_Expression *&left, ZCC_Expression *&right); diff --git a/src/zscript/zcc_errors.h b/src/zscript/zcc_errors.h index 7deb5737e..cb38a00d5 100644 --- a/src/zscript/zcc_errors.h +++ b/src/zscript/zcc_errors.h @@ -9,4 +9,6 @@ enum EZCCError ERR_recursive_definition = 20004 | ZCCERR_ERROR, ERR_not_a_member = 20005 | ZCCERR_ERROR, ERR_bad_symbol = 20006 | ZCCERR_ERROR, + ERR_cast_needs_1_parm = 20007 | ZCCERR_ERROR, + ERR_cast_not_possible = 20008 | ZCCERR_ERROR, }; diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index 47213b549..5dae12e78 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -234,6 +234,14 @@ struct ZCC_Expression : ZCC_TreeNode { EZCCExprType Operation; PType *Type; + + // Repurposes this node as an error node + void ToErrorNode() + { + Type = TypeError; + Operation = PEX_Nil; + NodeType = AST_Expression; + } }; struct ZCC_StateGoto : ZCC_StatePart From b66de4116d8ca22b31f05b20c28f131798fb0225 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 1 Nov 2013 21:28:00 -0500 Subject: [PATCH 191/232] Remove IsUnary() and IsBinary() - This information is already stored in the node's NodeType field, so there's no reason to go do a table lookup for it elsewhere. Must have been a brain fart when I wrote them in the first place. --- src/zscript/zcc_compile.cpp | 4 +- src/zscript/zcc_expr.cpp | 2 +- src/zscript/zcc_exprlist.h | 88 ++++++++++++++++++------------------- src/zscript/zcc_parser.h | 13 ------ 4 files changed, 47 insertions(+), 60 deletions(-) diff --git a/src/zscript/zcc_compile.cpp b/src/zscript/zcc_compile.cpp index b95bc33b7..5a3276a07 100644 --- a/src/zscript/zcc_compile.cpp +++ b/src/zscript/zcc_compile.cpp @@ -226,11 +226,11 @@ PSymbolConst *ZCCCompiler::CompileConstant(ZCC_ConstantDef *def) ZCC_Expression *ZCCCompiler::Simplify(ZCC_Expression *root) { - if (IsUnaryOp(root->Operation)) + if (root->NodeType == AST_ExprUnary) { return SimplifyUnary(static_cast<ZCC_ExprUnary *>(root)); } - else if (IsBinaryOp(root->Operation)) + else if (root->NodeType == AST_ExprBinary) { return SimplifyBinary(static_cast<ZCC_ExprBinary *>(root)); } diff --git a/src/zscript/zcc_expr.cpp b/src/zscript/zcc_expr.cpp index 3f5aec298..da9063fc9 100644 --- a/src/zscript/zcc_expr.cpp +++ b/src/zscript/zcc_expr.cpp @@ -12,7 +12,7 @@ ZCC_OpInfoType ZCC_OpInfo[PEX_COUNT_OF] = { -#define xx(a,n) { n, #a, NULL }, +#define xx(a,z) { #a, NULL }, #include "zcc_exprlist.h" }; diff --git a/src/zscript/zcc_exprlist.h b/src/zscript/zcc_exprlist.h index cbe78ef09..e36aedea6 100644 --- a/src/zscript/zcc_exprlist.h +++ b/src/zscript/zcc_exprlist.h @@ -1,57 +1,57 @@ // Name n-ary -xx(Nil, 0) +xx(Nil, ) -xx(ID, 0) -xx(Super, 0) -xx(Self, 0) -xx(ConstValue, 0) -xx(FuncCall, 0) -xx(ArrayAccess, 0) -xx(MemberAccess, 0) -xx(TypeRef, 0) +xx(ID, ) +xx(Super, ) +xx(Self, ) +xx(ConstValue, ) +xx(FuncCall, ) +xx(ArrayAccess, ) +xx(MemberAccess, ) +xx(TypeRef, ) -xx(PostInc, 1) -xx(PostDec, 1) +xx(PostInc, ) +xx(PostDec, ) -xx(PreInc, 1) -xx(PreDec, 1) -xx(Negate, 1) -xx(AntiNegate, 1) -xx(BitNot, 1) -xx(BoolNot, 1) -xx(SizeOf, 1) -xx(AlignOf, 1) +xx(PreInc, ) +xx(PreDec, ) +xx(Negate, ) +xx(AntiNegate, ) +xx(BitNot, ) +xx(BoolNot, ) +xx(SizeOf, ) +xx(AlignOf, ) -xx(Add, 2) -xx(Sub, 2) -xx(Mul, 2) -xx(Div, 2) -xx(Mod, 2) -xx(Pow, 2) -xx(CrossProduct, 2) -xx(DotProduct, 2) -xx(LeftShift, 2) -xx(RightShift, 2) -xx(Concat, 2) +xx(Add, ) +xx(Sub, ) +xx(Mul, ) +xx(Div, ) +xx(Mod, ) +xx(Pow, ) +xx(CrossProduct, ) +xx(DotProduct, ) +xx(LeftShift, ) +xx(RightShift, ) +xx(Concat, ) -xx(LT, 2) -xx(LTEQ, 2) -xx(LTGTEQ, 2) -xx(Is, 2) +xx(LT, ) +xx(LTEQ, ) +xx(LTGTEQ, ) +xx(Is, ) -xx(EQEQ, 2) -xx(APREQ, 2) +xx(EQEQ, ) +xx(APREQ, ) -xx(BitAnd, 2) -xx(BitOr, 2) -xx(BitXor, 2) -xx(BoolAnd, 2) -xx(BoolOr, 2) +xx(BitAnd, ) +xx(BitOr, ) +xx(BitXor, ) +xx(BoolAnd, ) +xx(BoolOr, ) -xx(Scope, 0) +xx(Scope, ) -xx(Trinary, 2) +xx(Trinary, ) -xx(Cast, 1) +xx(Cast, ) #undef xx diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index 5dae12e78..6512ee0f7 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -476,8 +476,6 @@ struct ZCC_OpProto struct ZCC_OpInfoType { - BYTE Nary:2; // n-ary-ness of operator - const char *OpName; ZCC_OpProto *Protos; @@ -497,17 +495,6 @@ void ZCC_InitOperators(); extern ZCC_OpInfoType ZCC_OpInfo[PEX_COUNT_OF]; -static inline bool IsUnaryOp(EZCCExprType op) -{ - assert((unsigned)op < (unsigned)PEX_COUNT_OF); - return ZCC_OpInfo[op].Nary == 1; -} -static inline bool IsBinaryOp(EZCCExprType op) -{ - assert((unsigned)op < (unsigned)PEX_COUNT_OF); - return ZCC_OpInfo[op].Nary == 2; -} - struct ZCC_AST { ZCC_AST() : TopNode(NULL) {} From 3063df4f74bab53846f9477be7555a359741a4e9 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 1 Nov 2013 21:45:02 -0500 Subject: [PATCH 192/232] Add single <-> double conversions. - With explicit casting now possible, converting from double to single precision floating point and back again needs to be possible, too. --- src/zscript/ast.cpp | 13 +++++++++++-- src/zscript/zcc_expr.cpp | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/zscript/ast.cpp b/src/zscript/ast.cpp index bba089a30..c7ebf801e 100644 --- a/src/zscript/ast.cpp +++ b/src/zscript/ast.cpp @@ -160,10 +160,15 @@ public: size_t len = mysnprintf(buf, countof(buf), "%08x", x); Add(buf, len); } - void AddFloat(double f) + void AddFloat(double f, bool single) { char buf[32]; size_t len = mysnprintf(buf, countof(buf), "%.4f", f); + if (single) + { + buf[len++] = 'f'; + buf[len] = '\0'; + } Add(buf, len); } private: @@ -501,7 +506,11 @@ static void PrintExprConstant(FLispString &out, ZCC_TreeNode *node) } else if (enode->Type == TypeFloat64) { - out.AddFloat(enode->DoubleVal); + out.AddFloat(enode->DoubleVal, false); + } + else if (enode->Type == TypeFloat32) + { + out.AddFloat(enode->DoubleVal, true); } else if (enode->Type == TypeName) { diff --git a/src/zscript/zcc_expr.cpp b/src/zscript/zcc_expr.cpp index da9063fc9..dc7a08d1c 100644 --- a/src/zscript/zcc_expr.cpp +++ b/src/zscript/zcc_expr.cpp @@ -613,6 +613,21 @@ static void DtoU32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) expr->Type = TypeUInt32; } +static void FtoD(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + // Constant single precision numbers are stored as doubles. + assert(expr->Type == TypeFloat32); + expr->Type = TypeFloat64; +} + +static void DtoF(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + // Truncate double precision to single precision. + float poop = (float)expr->DoubleVal; + expr->DoubleVal = poop; + expr->Type = TypeFloat32; +} + static void S32toS(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) { char str[16]; @@ -664,7 +679,10 @@ void ZCC_InitConversions() TypeSInt32->AddConversion(TypeFloat64, S32toD); TypeSInt32->AddConversion(TypeString, S32toS); + TypeFloat32->AddConversion(TypeFloat64, FtoD); + TypeFloat64->AddConversion(TypeUInt32, DtoU32); TypeFloat64->AddConversion(TypeSInt32, DtoS32); + TypeFloat64->AddConversion(TypeFloat32, DtoF); TypeFloat64->AddConversion(TypeString, DtoS); } From ec6624dfc767e9a65abe143a04c3fe6f58d0f4fe Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Fri, 1 Nov 2013 22:05:49 -0500 Subject: [PATCH 193/232] Prioritize single->double conversions for FindBestProto() - The binary form of ZCC_OpInfoType::FindBestProto() needs special handling for conversion from single to double precision floating point so that it doesn't choose an integer form over a floating point form when picking the best prototype. --- src/zscript/zcc_expr.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/zscript/zcc_expr.cpp b/src/zscript/zcc_expr.cpp index dc7a08d1c..32d0c9374 100644 --- a/src/zscript/zcc_expr.cpp +++ b/src/zscript/zcc_expr.cpp @@ -10,6 +10,8 @@ #define luai_nummod(a,b) ((a) - floor((a)/(b))*(b)) +static void FtoD(ZCC_ExprConstant *expr, FSharedStringArena &str_arena); + ZCC_OpInfoType ZCC_OpInfo[PEX_COUNT_OF] = { #define xx(a,z) { #a, NULL }, @@ -134,7 +136,19 @@ ZCC_OpProto *ZCC_OpInfoType::FindBestProto( { // one or both operator types are unreachable continue; } - int dist = MIN(dist1, dist2); + // Do not count F32->F64 conversions in the distance comparisons. If we do, then + // [[float32 (op) int]] will choose the integer version instead of the floating point + // version, which we do not want. + int test_dist1 = dist1, test_dist2 = dist2; + if (routes[0][cur_route1][0]->ConvertConstant == FtoD) + { + test_dist1--; + } + if (routes[1][cur_route2][0]->ConvertConstant == FtoD) + { + test_dist2--; + } + int dist = MIN(test_dist1, test_dist2); if (dist < best_low_dist) { best_low_dist = dist; From b14f768b681d52640735f39724c0efa1d31a5f87 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sun, 21 Dec 2014 21:57:30 -0600 Subject: [PATCH 194/232] Fix FxPick code emission - Fixed: Integer constants passed to pick() need to manually generate load instructions, since FxConstant::Emit() will just return a constant register with its value. - Fixed: VMFunctionBuilder::RegAvailability::Reuse() didn't actually calculate a proper mask. Also added another assert to this function. --- src/thingdef/thingdef_expression.cpp | 28 ++++++++++++++++++---------- src/zscript/vmbuilder.cpp | 3 ++- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 2395b0d0e..f95bfcdaf 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -2203,17 +2203,25 @@ ExpEmit FxPick::Emit(VMFunctionBuilder *build) for (unsigned i = 0; i < choices.Size(); ++i) { build->BackpatchToHere(jumptable + i); - ExpEmit casereg = choices[i]->Emit(build); - if (casereg.RegNum != resultreg.RegNum) - { // The result of the case is in a different register from what - // was expected. Copy it to the one we wanted. - - resultreg.Reuse(build); // This is really just for the assert in Reuse() - build->Emit(OP_MOVE, resultreg.RegNum, casereg.RegNum, 0); - resultreg.Free(build); + if (choices[i]->isConstant()) + { + int val = static_cast<FxConstant *>(choices[i])->GetValue().GetInt(); + build->EmitLoadInt(resultreg.RegNum, val); + } + else + { + ExpEmit casereg = choices[i]->Emit(build); + if (casereg.RegNum != resultreg.RegNum) + { // The result of the case is in a different register from what + // was expected. Copy it to the one we wanted. + + resultreg.Reuse(build); // This is really just for the assert in Reuse() + build->Emit(OP_MOVE, resultreg.RegNum, casereg.RegNum, 0); + resultreg.Free(build); + } + // Free this register so the remaining cases can use it. + casereg.Free(build); } - // Free this register so the remaining cases can use it. - casereg.Free(build); // All but the final case needs a jump to the end of the expression's code. if (i + 1 < choices.Size()) { diff --git a/src/zscript/vmbuilder.cpp b/src/zscript/vmbuilder.cpp index 2dff77cfc..d17efc1d9 100644 --- a/src/zscript/vmbuilder.cpp +++ b/src/zscript/vmbuilder.cpp @@ -423,8 +423,9 @@ void VMFunctionBuilder::RegAvailability::Return(int reg, int count) bool VMFunctionBuilder::RegAvailability::Reuse(int reg) { assert(reg >= 0 && reg <= 255); + assert(reg < MostUsed && "Attempt to reuse a register that was never used"); - VM_UWORD mask = reg & 31; + VM_UWORD mask = 1 << (reg & 31); int word = reg / 32; if (Used[word] & mask) From 10a2c0f58a85945273727c1f839e68d5341961d8 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@zdoom.fake> Date: Sun, 21 Dec 2014 22:03:16 -0600 Subject: [PATCH 195/232] Fixed: FxIntCast::Emit() should free the source register --- src/thingdef/thingdef_expression.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index f95bfcdaf..60f24ad95 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -440,6 +440,7 @@ ExpEmit FxIntCast::Emit(VMFunctionBuilder *build) ExpEmit from = basex->Emit(build); assert(!from.Konst); assert(basex->ValueType == VAL_Float); + from.Free(build); ExpEmit to(build, REGT_INT); build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_F2I); return to; From 9e3ed70021de7ff6317bca582a08815f647cb85d Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@users.noreply.github.com> Date: Tue, 30 Dec 2014 21:15:48 -0600 Subject: [PATCH 196/232] Add non-action function parsing to the DECORATE parser --- src/thingdef/thingdef_parse.cpp | 356 ++++++++++++++++++-------------- 1 file changed, 205 insertions(+), 151 deletions(-) diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 564dc35e2..0bb009f70 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -277,22 +277,184 @@ static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClassActor *cls) sc.MustGetToken(';'); } +//========================================================================== +// +// ParseArgListDef +// +// Parses the argument list from a function declaration. +// +//========================================================================== + +static void ParseArgListDef(FScanner &sc, PClassActor *cls, + TArray<PType *> &args, TArray<DWORD> &argflags) +{ + if (!sc.CheckToken(')')) + { + while (sc.TokenType != ')') + { + int flags = 0; + PType *type = NULL; + PClass *restrict = NULL; + + // Retrieve flags before type name + for (;;) + { + if (sc.CheckToken(TK_Coerce) || sc.CheckToken(TK_Native)) + { + } + else + { + break; + } + } + // Read the variable type + sc.MustGetAnyToken(); + switch (sc.TokenType) + { + case TK_Bool: + case TK_Int: + type = TypeSInt32; + break; + + case TK_Float: + type = TypeFloat64; + break; + + case TK_Sound: type = TypeSound; break; + case TK_String: type = TypeString; break; + case TK_Name: type = TypeName; break; + case TK_State: type = TypeState; break; + case TK_Color: type = TypeColor; break; + case TK_Class: + sc.MustGetToken('<'); + sc.MustGetToken(TK_Identifier); // Get class name + restrict = PClass::FindClass(sc.String); + if (restrict == NULL) + { + sc.ScriptMessage("Unknown class type %s", sc.String); + FScriptPosition::ErrorCounter++; + } + else + { + type = NewClassPointer(restrict); + } + sc.MustGetToken('>'); + break; + case TK_Ellipsis: + // Making the final type NULL signals a varargs function. + type = NULL; + sc.MustGetToken(')'); + sc.UnGet(); + break; + default: + sc.ScriptMessage ("Unknown variable type %s", sc.TokenName(sc.TokenType, sc.String).GetChars()); + type = TypeSInt32; + FScriptPosition::ErrorCounter++; + break; + } + // Read the optional variable name + if (!sc.CheckToken(',') && !sc.CheckToken(')')) + { + sc.MustGetToken(TK_Identifier); + } + else + { + sc.UnGet(); + } + + if (sc.CheckToken('=')) + { + flags |= VARF_Optional; + FxExpression *def = ParseParameter(sc, cls, type, true); + delete def; + } + + args.Push(type); + argflags.Push(flags); + sc.MustGetAnyToken(); + if (sc.TokenType != ',' && sc.TokenType != ')') + { + sc.ScriptError ("Expected ',' or ')' but got %s instead", sc.TokenName(sc.TokenType, sc.String).GetChars()); + } + } + } + sc.MustGetToken(';'); +} + +//========================================================================== +// +// ParseFunctionDef +// +// Parses a native function's parameters and adds it to the class, +// if possible. +// +//========================================================================== + +void ParseFunctionDef(FScanner &sc, PClassActor *cls, FName funcname, + TArray<PType *> &rets, DWORD funcflags, unsigned int error) +{ + assert(cls != NULL); + + const AFuncDesc *afd; + TArray<PType *> args; + TArray<DWORD> argflags; + + afd = FindFunction(funcname); + if (afd == NULL) + { + sc.ScriptMessage ("The function '%s' has not been exported from the executable.", funcname.GetChars()); + ++error; + } + sc.MustGetToken('('); + + if (funcflags & VARF_Method) + { + args.Push(NewClassPointer(cls)), argflags.Push(0); // implied self pointer + } + if (funcflags & VARF_Action) + { + args.Push(NewClassPointer(RUNTIME_CLASS(AActor))), argflags.Push(0); // implied stateowner pointer + args.Push(TypeState), argflags.Push(0); // implied callingstate pointer + } + ParseArgListDef(sc, cls, args, argflags); + + if (afd != NULL) + { + PFunction *sym = new PFunction(funcname); + sym->AddVariant(NewPrototype(rets, args), argflags, *(afd->VMPointer)); + sym->Flags = funcflags; + if (error) + { + FScriptPosition::ErrorCounter += error; + } + else if (cls->Symbols.AddSymbol(sym) == NULL) + { + delete sym; + sc.ScriptMessage ("'%s' is already defined in class '%s'.", + funcname.GetChars(), cls->TypeName.GetChars()); + FScriptPosition::ErrorCounter++; + } + } +} + //========================================================================== // // ParseNativeVariable // -// Parses a native variable declaration. +// Parses a native variable or non-action function declaration. // //========================================================================== static void ParseNativeVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cls) { PType *valuetype; + unsigned int error = 0; if (sc.LumpNum == -1 || Wads.GetLumpFile(sc.LumpNum) > 0) { sc.ScriptMessage ("variables can only be imported by internal class and actor definitions!"); FScriptPosition::ErrorCounter++; + error++; } // Read the type and make sure it's int or float. @@ -300,6 +462,7 @@ static void ParseNativeVariable (FScanner &sc, PSymbolTable *symt, PClassActor * switch (sc.TokenType) { case TK_Int: + case TK_Bool: valuetype = TypeSInt32; break; @@ -328,39 +491,51 @@ static void ParseNativeVariable (FScanner &sc, PSymbolTable *symt, PClassActor * sc.MustGetToken(TK_Identifier); FName symname = sc.String; - if (sc.CheckToken('[')) + if (sc.CheckToken('(')) { - FxExpression *expr = ParseExpression (sc, cls); - if (!expr->isConstant()) - { - sc.ScriptError("Array size must be constant"); - } - int maxelems = static_cast<FxConstant *>(expr)->GetValue().GetInt(); - delete expr; - sc.MustGetToken(']'); - valuetype = NewArray(valuetype, maxelems); - } - sc.MustGetToken(';'); + TArray<PType *> rets; - const FVariableInfo *vi = FindVariable(symname, cls); - if (vi == NULL) - { - sc.ScriptError("Unknown native variable '%s'", symname.GetChars()); - } - - PField *sym = new PField(symname, valuetype, VARF_Native); - sym->Offset = (unsigned)vi->address; // todo - - if (symt->AddSymbol(sym) == NULL) - { - delete sym; - sc.ScriptMessage ("'%s' is already defined in '%s'.", - symname.GetChars(), cls? cls->TypeName.GetChars() : "Global"); - FScriptPosition::ErrorCounter++; + rets.Push(valuetype); + sc.UnGet(); + ParseFunctionDef(sc, cls, symname, rets, VARF_Method, error); + return; } else { - cls->Fields.Push(sym); + if (sc.CheckToken('[')) + { + FxExpression *expr = ParseExpression (sc, cls); + if (!expr->isConstant()) + { + sc.ScriptError("Array size must be constant"); + } + int maxelems = static_cast<FxConstant *>(expr)->GetValue().GetInt(); + delete expr; + sc.MustGetToken(']'); + valuetype = NewArray(valuetype, maxelems); + } + sc.MustGetToken(';'); + + const FVariableInfo *vi = FindVariable(symname, cls); + if (vi == NULL) + { + sc.ScriptError("Unknown native variable '%s'", symname.GetChars()); + } + + PField *sym = new PField(symname, valuetype, VARF_Native); + sym->Offset = (unsigned)vi->address; // todo + + if (symt->AddSymbol(sym) == NULL) + { + delete sym; + sc.ScriptMessage ("'%s' is already defined in '%s'.", + symname.GetChars(), cls? cls->TypeName.GetChars() : "Global"); + FScriptPosition::ErrorCounter++; + } + else + { + cls->Fields.Push(sym); + } } } @@ -908,11 +1083,8 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag) static void ParseActionDef (FScanner &sc, PClassActor *cls) { unsigned int error = 0; - const AFuncDesc *afd; FName funcname; TArray<PType *> rets; - TArray<PType *> args; - TArray<DWORD> argflags; if (sc.LumpNum == -1 || Wads.GetLumpFile(sc.LumpNum) > 0) { @@ -928,125 +1100,7 @@ static void ParseActionDef (FScanner &sc, PClassActor *cls) } sc.MustGetToken(TK_Identifier); funcname = sc.String; - afd = FindFunction(sc.String); - if (afd == NULL) - { - sc.ScriptMessage ("The function '%s' has not been exported from the executable.", sc.String); - ++error; - } - args.Push(NewClassPointer(cls)), argflags.Push(0); // implied self pointer - args.Push(NewClassPointer(RUNTIME_CLASS(AActor))), argflags.Push(0); // implied stateowner pointer - args.Push(TypeState), argflags.Push(0); // implied callingstate pointer - - sc.MustGetToken('('); - if (!sc.CheckToken(')')) - { - while (sc.TokenType != ')') - { - int flags = 0; - PType *type = NULL; - PClass *restrict = NULL; - - // Retrieve flags before type name - for (;;) - { - if (sc.CheckToken(TK_Coerce) || sc.CheckToken(TK_Native)) - { - } - else - { - break; - } - } - // Read the variable type - sc.MustGetAnyToken(); - switch (sc.TokenType) - { - case TK_Bool: - case TK_Int: - type = TypeSInt32; - break; - - case TK_Float: - type = TypeFloat64; - break; - - case TK_Sound: type = TypeSound; break; - case TK_String: type = TypeString; break; - case TK_Name: type = TypeName; break; - case TK_State: type = TypeState; break; - case TK_Color: type = TypeColor; break; - case TK_Class: - sc.MustGetToken('<'); - sc.MustGetToken(TK_Identifier); // Get class name - restrict = PClass::FindClass(sc.String); - if (restrict == NULL) - { - sc.ScriptMessage("Unknown class type %s", sc.String); - FScriptPosition::ErrorCounter++; - } - else - { - type = NewClassPointer(restrict); - } - sc.MustGetToken('>'); - break; - case TK_Ellipsis: - // Making the final type NULL signals a varargs function. - type = NULL; - sc.MustGetToken(')'); - sc.UnGet(); - break; - default: - sc.ScriptMessage ("Unknown variable type %s", sc.TokenName(sc.TokenType, sc.String).GetChars()); - type = TypeSInt32; - FScriptPosition::ErrorCounter++; - break; - } - // Read the optional variable name - if (!sc.CheckToken(',') && !sc.CheckToken(')')) - { - sc.MustGetToken(TK_Identifier); - } - else - { - sc.UnGet(); - } - - if (sc.CheckToken('=')) - { - flags |= VARF_Optional; - FxExpression *def = ParseParameter(sc, cls, type, true); - delete def; - } - - args.Push(type); - argflags.Push(flags); - sc.MustGetAnyToken(); - if (sc.TokenType != ',' && sc.TokenType != ')') - { - sc.ScriptError ("Expected ',' or ')' but got %s instead", sc.TokenName(sc.TokenType, sc.String).GetChars()); - } - } - } - sc.MustGetToken(';'); - if (afd != NULL) - { - PFunction *sym = new PFunction(funcname); - sym->AddVariant(NewPrototype(rets, args), argflags, *(afd->VMPointer)); - sym->Flags = VARF_Method | VARF_Action; - if (error) - { - FScriptPosition::ErrorCounter += error; - } - else if (cls->Symbols.AddSymbol(sym) == NULL) - { - delete sym; - sc.ScriptMessage ("'%s' is already defined in class '%s'.", - funcname.GetChars(), cls->TypeName.GetChars()); - FScriptPosition::ErrorCounter++; - } - } + ParseFunctionDef(sc, cls, funcname, rets, VARF_Method | VARF_Action, error); } //========================================================================== From c6c2b219013499c7ca2f420b50ab0120fd484f8d Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@users.noreply.github.com> Date: Tue, 30 Dec 2014 23:31:07 -0600 Subject: [PATCH 197/232] Add FxVMFunctionCall class - This replaces the general extensibility that had existed formerly in thingdef_function.cpp. Parameter parsing for function calls is shared with state parameter parsing. Functions are defined exactly in the same way as action functions, but without the 'action' keyword. --- src/thingdef/thingdef.h | 2 + src/thingdef/thingdef_exp.cpp | 13 +- src/thingdef/thingdef_exp.h | 19 +++ src/thingdef/thingdef_expression.cpp | 103 ++++++++++++++ src/thingdef/thingdef_states.cpp | 202 +++++++++++++++------------ src/zscript/vmbuilder.h | 1 + 6 files changed, 243 insertions(+), 97 deletions(-) diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index 21074b9f2..90dd83750 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -188,6 +188,8 @@ AFuncDesc *FindFunction(const char * string); void ParseStates(FScanner &sc, PClassActor *actor, AActor *defaults, Baggage &bag); +void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray<FxExpression *> &out_params, + PFunction *afd, FString statestring, FStateDefinitions *statedef); PFunction *FindGlobalActionFunction(const char *name); diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index 92e5ab686..5b7c1f0f4 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -459,16 +459,21 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) FName identifier = FName(sc.String); if (sc.CheckToken('(')) { - FArgumentList *args = NULL; + FArgumentList *args = new FArgumentList; + PFunction *func = dyn_cast<PFunction>(cls->Symbols.FindSymbol(identifier, true)); try { - if (!sc.CheckToken(')')) + if (func != NULL) + { + sc.UnGet(); + ParseFunctionParameters(sc, cls, *args, func, "", NULL); + return new FxVMFunctionCall(func, args, sc); + } + else if (!sc.CheckToken(')')) { - args = new FArgumentList; do { args->Push(ParseExpressionM (sc, cls)); - } while (sc.CheckToken(',')); sc.MustGetToken(')'); diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 1c840c19b..8d3c162df 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -782,6 +782,25 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxVMFunctionCall +// +//========================================================================== + +class FxVMFunctionCall : public FxExpression +{ + PFunction *Function; + FArgumentList *ArgList; + PType *ReturnType; + +public: + FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos); + ~FxVMFunctionCall(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxGlobalFunctionCall diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 60f24ad95..5fec0cf45 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3004,6 +3004,109 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) return dest; } +//========================================================================== +// +// FxVMFunctionCall +// +//========================================================================== + +FxVMFunctionCall::FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos) +: FxExpression(pos) +{ + Function = func; + ArgList = args; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxVMFunctionCall::~FxVMFunctionCall() +{ + SAFE_DELETE(ArgList); +} + +//========================================================================== +// +// FxVMFunctionCall :: Resolve +// +//========================================================================== + +FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + bool failed = false; + + if (ArgList != NULL) + { + for (unsigned i = 0; i < ArgList->Size(); i++) + { + (*ArgList)[i] = (*ArgList)[i]->Resolve(ctx); + if ((*ArgList)[i] == NULL) failed = true; + } + } + if (failed) + { + delete this; + return NULL; + } + TArray<PType *> &rets = Function->Variants[0].Proto->ReturnTypes; + assert(rets.Size() == 1); + ReturnType = rets[0]; + // If more types are added to ParseNativeVariable(), add them here too. + if (rets[0] == TypeSInt32) ValueType = VAL_Int; + else if (rets[0] == TypeFloat64) ValueType = VAL_Float; + else if (rets[0] == TypeAngle) ValueType = VAL_Angle; + else if (rets[0] == TypeFixed) ValueType = VAL_Fixed; + else + { + ValueType = VAL_Int; + assert(0 && "Unhandled return type in FxVMFunctionCall::Resolve"); + } + return this; +} + +//========================================================================== +// +// Assumption: This call is being made to generate code inside an action +// method, so the first three address registers are all set up for such a +// function. (self, stateowner, callingstate) +// +//========================================================================== + +ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) +{ + assert(build->Registers[REGT_POINTER].GetMostUsed() >= 3); + int count = ArgList->Size(); + + // Emit code to pass implied parameters + if (Function->Flags & VARF_Method) + { + build->Emit(OP_PARAM, 0, REGT_POINTER, 0); + count += 1; + } + if (Function->Flags & VARF_Action) + { + build->Emit(OP_PARAM, 0, REGT_POINTER, 1); + build->Emit(OP_PARAM, 0, REGT_POINTER, 2); + count += 2; + } + // Emit code to pass explicit parameters + for (unsigned i = 0; i < ArgList->Size(); ++i) + { + (*ArgList)[i]->Emit(build); + } + // Get a register to store the return value in + assert(ReturnType != NULL); + ExpEmit reg(build, ReturnType->GetRegType()); + // Emit the call itself + build->Emit(OP_CALL_K, build->GetConstantAddress(Function->Variants[0].Implementation, ATAG_OBJECT), count, 1); + build->Emit(OP_RESULT, 0, reg.RegType, reg.RegNum); + return reg; +} + //========================================================================== // // diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index fec49cc7c..041d3790e 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -326,99 +326,7 @@ do_stop: if (afd != NULL) { tcall->Function = afd->Variants[0].Implementation; - const TArray<PType *> ¶ms = afd->Variants[0].Proto->ArgumentTypes; - const TArray<DWORD> ¶mflags = afd->Variants[0].ArgFlags; - int numparams = (int)params.Size(); - int pnum = 0; - if (afd->Flags & VARF_Method) - { - numparams--; - pnum++; - } - if (afd->Flags & VARF_Action) - { - numparams -= 2; - pnum += 2; - } - if (numparams > 0) - { - int v; - - if (!(paramflags[pnum] & VARF_Optional)) - { - sc.MustGetStringName("("); - } - else - { - if (!sc.CheckString("(")) - { - goto endofstate; - } - } - - while (numparams > 0) - { - FxExpression *x; - if (params[pnum] == TypeState && sc.CheckNumber()) - { - // Special case: State label as an offset - if (sc.Number > 0 && statestring.Len() > 1) - { - sc.ScriptError("You cannot use state jumps commands with a jump offset on multistate definitions\n"); - } - - v = sc.Number; - if (v<0) - { - sc.ScriptError("Negative jump offsets are not allowed"); - } - - if (v > 0) - { - x = new FxStateByIndex(bag.statedef.GetStateCount() + v, sc); - } - else - { - x = new FxConstant((FState*)NULL, sc); - } - } - else - { - // Use the generic parameter parser for everything else - x = ParseParameter(sc, bag.Info, params[pnum], false); - } - tcall->Parameters.Push(new FxParameter(x)); - pnum++; - numparams--; - if (numparams > 0) - { - if (params[pnum] == NULL) - { // varargs function - if (sc.CheckString(")")) - { - goto endofstate; - } - pnum--; - numparams++; - } - else if ((paramflags[pnum] & VARF_Optional) && sc.CheckString(")")) - { - goto endofstate; - } - sc.MustGetStringName (","); - } - } - sc.MustGetStringName(")"); - } - else - { - sc.MustGetString(); - if (sc.Compare("(")) - { - sc.ScriptError("You cannot pass parameters to '%s'\n",sc.String); - } - sc.UnGet(); - } + ParseFunctionParameters(sc, bag.Info, tcall->Parameters, afd, statestring, &bag.statedef); goto endofstate; } sc.ScriptError("Invalid state parameter %s\n", sc.String); @@ -448,3 +356,111 @@ endofstate: sc.SetEscape(true); // re-enable escape sequences } +//========================================================================== +// +// ParseFunctionParameters +// +// Parses the parameters for a VM function. Called by both ParseStates +// (which will set statestring and statedef) and by ParseExpression0 (which +// will not set them). The first token returned by the scanner when entering +// this function should be '('. +// +//========================================================================== + +void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray<FxExpression *> &out_params, + PFunction *afd, FString statestring, FStateDefinitions *statedef) +{ + const TArray<PType *> ¶ms = afd->Variants[0].Proto->ArgumentTypes; + const TArray<DWORD> ¶mflags = afd->Variants[0].ArgFlags; + int numparams = (int)params.Size(); + int pnum = 0; + if (afd->Flags & VARF_Method) + { + numparams--; + pnum++; + } + if (afd->Flags & VARF_Action) + { + numparams -= 2; + pnum += 2; + } + if (numparams > 0) + { + int v; + + if (!(paramflags[pnum] & VARF_Optional)) + { + sc.MustGetStringName("("); + } + else + { + if (!sc.CheckString("(")) + { + return; + } + } + + while (numparams > 0) + { + FxExpression *x; + if (statedef != NULL && params[pnum] == TypeState && sc.CheckNumber()) + { + // Special case: State label as an offset + if (sc.Number > 0 && statestring.Len() > 1) + { + sc.ScriptError("You cannot use state jumps commands with a jump offset on multistate definitions\n"); + } + + v = sc.Number; + if (v<0) + { + sc.ScriptError("Negative jump offsets are not allowed"); + } + + if (v > 0) + { + x = new FxStateByIndex(statedef->GetStateCount() + v, sc); + } + else + { + x = new FxConstant((FState*)NULL, sc); + } + } + else + { + // Use the generic parameter parser for everything else + x = ParseParameter(sc, cls, params[pnum], false); + } + out_params.Push(new FxParameter(x)); + pnum++; + numparams--; + if (numparams > 0) + { + if (params[pnum] == NULL) + { // varargs function + if (sc.CheckString(")")) + { + return; + } + pnum--; + numparams++; + } + else if ((paramflags[pnum] & VARF_Optional) && sc.CheckString(")")) + { + return; + } + sc.MustGetStringName (","); + } + } + sc.MustGetStringName(")"); + } + else + { + sc.MustGetString(); + if (sc.Compare("(")) + { + sc.ScriptError("You cannot pass parameters to '%s'\n", afd->SymbolName.GetChars()); + } + sc.UnGet(); + } +} diff --git a/src/zscript/vmbuilder.h b/src/zscript/vmbuilder.h index 74537c857..b8b1df848 100644 --- a/src/zscript/vmbuilder.h +++ b/src/zscript/vmbuilder.h @@ -11,6 +11,7 @@ public: { public: RegAvailability(); + int GetMostUsed() { return MostUsed; } int Get(int count); // Returns the first register in the range void Return(int reg, int count); bool Reuse(int regnum); From 85a20423945b0437d2cc8ebd17777efdfb896e4d Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@users.noreply.github.com> Date: Tue, 30 Dec 2014 23:31:21 -0600 Subject: [PATCH 198/232] Reimplement CheckClass and IsPointerEqual functions - The definition of FxGlobalFunctionCall_CheckClass was big and scary. I would say this is a big improvement, since now it gets to leverage the same framework that action functions use. - The definition of FxGlobalFunctionCall_IsPointerEqual was not so big and scary, so this can't be called so much of an improvement as CheckClass was. (Which is not to say that it isn't better anyway.) --- src/thingdef/thingdef_codeptr.cpp | 61 +++++++++++++++++++++++++++++++ wadsrc/static/actors/actor.txt | 3 ++ 2 files changed, 64 insertions(+) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 49c30be5a..147a4c192 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -152,6 +152,67 @@ bool ACustomInventory::CallStateChain (AActor *actor, FState *state) return !!result; } +//========================================================================== +// +// CheckClass +// +// NON-ACTION function to check a pointer's class. +// +//========================================================================== + +DEFINE_ACTION_FUNCTION(AActor, CheckClass) +{ + if (numret > 0) + { + assert(ret != NULL); + PARAM_PROLOGUE; + PARAM_OBJECT (self, AActor); + PARAM_CLASS (checktype, AActor); + PARAM_INT_OPT (pick_pointer) { pick_pointer = AAPTR_DEFAULT; } + PARAM_BOOL_OPT (match_superclass) { match_superclass = false; } + + self = COPY_AAPTR(self, pick_pointer); + if (self == NULL) + { + ret->SetInt(false); + } + else if (match_superclass) + { + ret->SetInt(self->IsKindOf(checktype)); + } + else + { + ret->SetInt(self->GetClass() == checktype); + } + return 1; + } + return 0; +} + +//========================================================================== +// +// IsPointerEqual +// +// NON-ACTION function to check if two pointers are equal. +// +//========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, IsPointerEqual) +{ + if (numret > 0) + { + assert(ret != NULL); + PARAM_PROLOGUE; + PARAM_OBJECT (self, AActor); + PARAM_INT (ptr_select1); + PARAM_INT (ptr_select2); + + ret->SetInt(COPY_AAPTR(self, ptr_select1) == COPY_AAPTR(self, ptr_select2)); + return 1; + } + return 0; +} + //========================================================================== // // A_RearrangePointers diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index d4910df91..d20a7d0ed 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -66,6 +66,9 @@ ACTOR Actor native //: Thinker native fixed_t meleerange; native fixed_t speed; + native bool CheckClass(class<Actor> checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false); + native bool IsPointerEqual(int ptr_select1, int ptr_select2); + // Meh, MBF redundant functions. Only for DeHackEd support. action native A_Turn(float angle = 0); action native A_LineEffect(int boomspecial = 0, int tag = 0); From 8c105ff3a0fbb1e0469dca843eaa7fca06641a1f Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@users.noreply.github.com> Date: Sat, 3 Jan 2015 22:45:11 -0600 Subject: [PATCH 199/232] Use FxVMFunctionCall in FStateTempCall - Leveraging FxVMFunctionCall simplifies FinishThingdef() slightly. --- src/thingdef/thingdef.cpp | 34 +++++++---------- src/thingdef/thingdef.h | 5 +-- src/thingdef/thingdef_exp.h | 5 ++- src/thingdef/thingdef_expression.cpp | 57 ++++++++++++++++++++-------- src/thingdef/thingdef_states.cpp | 33 ++++++++++++---- 5 files changed, 86 insertions(+), 48 deletions(-) diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 0a02e2763..a1350086b 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -276,7 +276,7 @@ static void DumpFunction(FILE *dump, VMScriptFunction *sfunc, const char *label, static void FinishThingdef() { int errorcount = 0; - unsigned i, j; + unsigned i; int codesize = 0; #if 1 @@ -289,34 +289,26 @@ static void FinishThingdef() FStateTempCall *tcall = StateTempCalls[i]; VMFunction *func; - assert(tcall->Function != NULL); - if (tcall->Parameters.Size() == 0) + assert(tcall->Call != NULL); + if (tcall->Call->GetArgCount() == 0) { - func = tcall->Function; + // There are no arguments, so we can call this function directly + // without wrapping it in an anonymous function. + func = tcall->Call->GetVMFunction(); } else { FCompileContext ctx(tcall->ActorClass); - for (j = 0; j < tcall->Parameters.Size(); ++j) - { - tcall->Parameters[j]->Resolve(ctx); - } + tcall->Call->Resolve(ctx); VMFunctionBuilder buildit; + // Allocate registers used to pass parameters in. // self, stateowner, state (all are pointers) buildit.Registers[REGT_POINTER].Get(3); - // Emit code to pass the standard action function parameters. - buildit.Emit(OP_PARAM, 0, REGT_POINTER, 0); - buildit.Emit(OP_PARAM, 0, REGT_POINTER, 1); - buildit.Emit(OP_PARAM, 0, REGT_POINTER, 2); - // Emit code for action parameters. - for (j = 0; j < tcall->Parameters.Size(); ++j) - { - FxExpression *p = /*new FxParameter*/(tcall->Parameters[j]); - p->Emit(&buildit); - delete p; - } - buildit.Emit(OP_TAIL_K, buildit.GetConstantAddress(tcall->Function, ATAG_OBJECT), NAP + j, 0); + + // Emit a tail call via FxVMFunctionCall + tcall->Call->Emit(&buildit, true); + VMScriptFunction *sfunc = buildit.MakeFunction(); sfunc->NumArgs = NAP; func = sfunc; @@ -330,6 +322,8 @@ static void FinishThingdef() codesize += sfunc->CodeSize; } } + delete tcall->Call; + tcall->Call = NULL; for (int k = 0; k < tcall->NumStates; ++k) { tcall->ActorClass->OwnedStates[tcall->FirstState + k].SetAction(func); diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index 90dd83750..de8d524a1 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -119,11 +119,10 @@ public: struct FStateTempCall { - FStateTempCall() : ActorClass(NULL), Function(NULL), FirstState(0), NumStates(0) {} + FStateTempCall() : ActorClass(NULL), Call(NULL), FirstState(0), NumStates(0) {} PClassActor *ActorClass; - VMFunction *Function; - TArray<FxExpression *> Parameters; + class FxVMFunctionCall *Call; int FirstState; int NumStates; }; diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 8d3c162df..8608557ef 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -798,7 +798,10 @@ public: FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos); ~FxVMFunctionCall(); FxExpression *Resolve(FCompileContext&); - ExpEmit Emit(VMFunctionBuilder *build); + virtual ExpEmit Emit(VMFunctionBuilder *build); + ExpEmit Emit(VMFunctionBuilder *build, bool tailcall); + unsigned GetArgCount() { return ArgList == NULL ? 0 : ArgList->Size(); } + VMFunction *GetVMFunction() { return Function->Variants[0].Implementation; } }; //========================================================================== diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 5fec0cf45..af6f7b52a 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3053,17 +3053,23 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) return NULL; } TArray<PType *> &rets = Function->Variants[0].Proto->ReturnTypes; - assert(rets.Size() == 1); - ReturnType = rets[0]; - // If more types are added to ParseNativeVariable(), add them here too. - if (rets[0] == TypeSInt32) ValueType = VAL_Int; - else if (rets[0] == TypeFloat64) ValueType = VAL_Float; - else if (rets[0] == TypeAngle) ValueType = VAL_Angle; - else if (rets[0] == TypeFixed) ValueType = VAL_Fixed; + if (rets.Size() == NULL) + { + ReturnType = TypeVoid; + } else { - ValueType = VAL_Int; - assert(0 && "Unhandled return type in FxVMFunctionCall::Resolve"); + ReturnType = rets[0]; + // If more types are added to ParseNativeVariable(), add them here too. + if (rets[0] == TypeSInt32) ValueType = VAL_Int; + else if (rets[0] == TypeFloat64) ValueType = VAL_Float; + else if (rets[0] == TypeAngle) ValueType = VAL_Angle; + else if (rets[0] == TypeFixed) ValueType = VAL_Fixed; + else + { + ValueType = VAL_Int; + assert(0 && "Unhandled return type in FxVMFunctionCall::Resolve"); + } } return this; } @@ -3077,6 +3083,11 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) //========================================================================== ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) +{ + return Emit(build, false); +} + +ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall) { assert(build->Registers[REGT_POINTER].GetMostUsed() >= 3); int count = ArgList->Size(); @@ -3098,13 +3109,27 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) { (*ArgList)[i]->Emit(build); } - // Get a register to store the return value in - assert(ReturnType != NULL); - ExpEmit reg(build, ReturnType->GetRegType()); - // Emit the call itself - build->Emit(OP_CALL_K, build->GetConstantAddress(Function->Variants[0].Implementation, ATAG_OBJECT), count, 1); - build->Emit(OP_RESULT, 0, reg.RegType, reg.RegNum); - return reg; + // Get a constant register for this function + int funcaddr = build->GetConstantAddress(Function->Variants[0].Implementation, ATAG_OBJECT); + // Emit the call + if (tailcall) + { // Tail call + build->Emit(OP_TAIL_K, funcaddr, count, 0); + return ExpEmit(); + } + else if (ReturnType != TypeVoid) + { // Call, expecting one result + assert(ReturnType != NULL); + ExpEmit reg(build, ReturnType->GetRegType()); + build->Emit(OP_CALL_K, funcaddr, count, 1); + build->Emit(OP_RESULT, 0, reg.RegType, reg.RegNum); + return reg; + } + else + { // Call, expecting no results + build->Emit(OP_CALL_K, funcaddr, count, 0); + return ExpEmit(); + } } //========================================================================== diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index 041d3790e..d1c1f8209 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -72,24 +72,25 @@ bool DoActionSpecials(FScanner &sc, FState & state, Baggage &bag, FStateTempCall int min_args, max_args; FString specname = sc.String; + FArgumentList *args = new FArgumentList; int special = P_FindLineSpecial(sc.String, &min_args, &max_args); if (special > 0 && min_args >= 0) { - tcall->Parameters.Push(new FxParameter(new FxConstant(special, sc))); + args->Push(new FxParameter(new FxConstant(special, sc))); + i = 0; // Make this consistent with all other parameter parsing if (sc.CheckToken('(')) { - for (i = 0; i < 5;) + while (i < 5) { - tcall->Parameters.Push(new FxParameter(new FxIntCast(ParseExpression(sc, bag.Info)))); + args->Push(new FxParameter(new FxIntCast(ParseExpression(sc, bag.Info)))); i++; if (!sc.CheckToken (',')) break; } sc.MustGetToken (')'); } - else i=0; if (i < min_args) { @@ -100,7 +101,7 @@ bool DoActionSpecials(FScanner &sc, FState & state, Baggage &bag, FStateTempCall sc.ScriptError ("Too many arguments to %s", specname.GetChars()); } - tcall->Function = FindGlobalActionFunction("A_CallSpecial")->Variants[0].Implementation; + tcall->Call = new FxVMFunctionCall(FindGlobalActionFunction("A_CallSpecial"), args, sc); return true; } return false; @@ -143,6 +144,7 @@ void ParseStates(FScanner &sc, PClassActor * actor, AActor * defaults, Baggage & FState state; char lastsprite[5] = ""; FStateTempCall *tcall = NULL; + FArgumentList *args = NULL; sc.MustGetStringName ("{"); sc.SetEscape(false); // disable escape sequences in the state parser @@ -325,8 +327,19 @@ do_stop: PFunction *afd = dyn_cast<PFunction>(bag.Info->Symbols.FindSymbol(FName(sc.String, true), true)); if (afd != NULL) { - tcall->Function = afd->Variants[0].Implementation; - ParseFunctionParameters(sc, bag.Info, tcall->Parameters, afd, statestring, &bag.statedef); + // When creating the FxVMFunctionCall, we only pass args if there are any. + // So if the previous call had no args, then we can use the argument list + // allocated for it. Otherwise, we need to create a new one. + if (args == NULL) + { + args = new FArgumentList; + } + ParseFunctionParameters(sc, bag.Info, *args, afd, statestring, &bag.statedef); + tcall->Call = new FxVMFunctionCall(afd, args->Size() > 0 ? args : NULL, sc); + if (args->Size() > 0) + { + args = NULL; + } goto endofstate; } sc.ScriptError("Invalid state parameter %s\n", sc.String); @@ -339,7 +352,7 @@ endofstate: sc.ScriptError ("Invalid frame character string '%s'", statestring.GetChars()); count = -count; } - if (tcall->Function != NULL) + if (tcall->Call != NULL) { tcall->ActorClass = actor; tcall->FirstState = bag.statedef.GetStateCount() - count; @@ -353,6 +366,10 @@ endofstate: { delete tcall; } + if (args != NULL) + { + delete args; + } sc.SetEscape(true); // re-enable escape sequences } From 320fb9aec566196e92a094469ec2aea57262e3ee Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@users.noreply.github.com> Date: Tue, 6 Jan 2015 19:44:20 -0600 Subject: [PATCH 200/232] Allow empty parameter lists for action functions without parameters - Using A_Scream() in a state instead of A_Scream is now valid. --- src/thingdef/thingdef_states.cpp | 111 +++++++++++++++---------------- 1 file changed, 55 insertions(+), 56 deletions(-) diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index d1c1f8209..26c4deddb 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -391,6 +391,8 @@ void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray<FxExpression const TArray<DWORD> ¶mflags = afd->Variants[0].ArgFlags; int numparams = (int)params.Size(); int pnum = 0; + bool zeroparm; + if (afd->Flags & VARF_Method) { numparams--; @@ -401,83 +403,80 @@ void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray<FxExpression numparams -= 2; pnum += 2; } - if (numparams > 0) + assert(numparams >= 0); + zeroparm = numparams == 0; + if (numparams > 0 && !(paramflags[pnum] & VARF_Optional)) { - int v; - - if (!(paramflags[pnum] & VARF_Optional)) + sc.MustGetStringName("("); + } + else + { + if (!sc.CheckString("(")) { - sc.MustGetStringName("("); + return; } - else + } + while (numparams > 0) + { + FxExpression *x; + if (statedef != NULL && params[pnum] == TypeState && sc.CheckNumber()) { - if (!sc.CheckString("(")) + // Special case: State label as an offset + if (sc.Number > 0 && statestring.Len() > 1) { - return; + sc.ScriptError("You cannot use state jumps commands with a jump offset on multistate definitions\n"); } - } - - while (numparams > 0) - { - FxExpression *x; - if (statedef != NULL && params[pnum] == TypeState && sc.CheckNumber()) + + int v = sc.Number; + if (v < 0) { - // Special case: State label as an offset - if (sc.Number > 0 && statestring.Len() > 1) - { - sc.ScriptError("You cannot use state jumps commands with a jump offset on multistate definitions\n"); - } + sc.ScriptError("Negative jump offsets are not allowed"); + } - v = sc.Number; - if (v<0) - { - sc.ScriptError("Negative jump offsets are not allowed"); - } - - if (v > 0) - { - x = new FxStateByIndex(statedef->GetStateCount() + v, sc); - } - else - { - x = new FxConstant((FState*)NULL, sc); - } + if (v > 0) + { + x = new FxStateByIndex(statedef->GetStateCount() + v, sc); } else { - // Use the generic parameter parser for everything else - x = ParseParameter(sc, cls, params[pnum], false); + x = new FxConstant((FState*)NULL, sc); } - out_params.Push(new FxParameter(x)); - pnum++; - numparams--; - if (numparams > 0) - { - if (params[pnum] == NULL) - { // varargs function - if (sc.CheckString(")")) - { - return; - } - pnum--; - numparams++; - } - else if ((paramflags[pnum] & VARF_Optional) && sc.CheckString(")")) + } + else + { + // Use the generic parameter parser for everything else + x = ParseParameter(sc, cls, params[pnum], false); + } + out_params.Push(new FxParameter(x)); + pnum++; + numparams--; + if (numparams > 0) + { + if (params[pnum] == NULL) + { // varargs function + if (sc.CheckString(")")) { return; } - sc.MustGetStringName (","); + pnum--; + numparams++; } + else if ((paramflags[pnum] & VARF_Optional) && sc.CheckString(")")) + { + return; + } + sc.MustGetStringName (","); } - sc.MustGetStringName(")"); } - else + if (zeroparm) { - sc.MustGetString(); - if (sc.Compare("(")) + if (!sc.CheckString(")")) { sc.ScriptError("You cannot pass parameters to '%s'\n", afd->SymbolName.GetChars()); } - sc.UnGet(); + } + else + { + sc.MustGetStringName(")"); } } From 910451a351f71d8637683253490218ea4bfee799 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@users.noreply.github.com> Date: Tue, 6 Jan 2015 19:50:01 -0600 Subject: [PATCH 201/232] Return a FxVMFunctionCall from DoActionSpecials() - DoActionSpecials no longer sets the function call in FStateTempCall. Instead, it returns the function so the caller can do it. --- src/thingdef/thingdef_states.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index 26c4deddb..2d676b642 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -66,7 +66,7 @@ TDeletingArray<FStateTempCall *> StateTempCalls; // handles action specials as code pointers // //========================================================================== -bool DoActionSpecials(FScanner &sc, FState & state, Baggage &bag, FStateTempCall *tcall) +FxVMFunctionCall *DoActionSpecials(FScanner &sc, FState & state, Baggage &bag) { int i; int min_args, max_args; @@ -100,11 +100,9 @@ bool DoActionSpecials(FScanner &sc, FState & state, Baggage &bag, FStateTempCall { sc.ScriptError ("Too many arguments to %s", specname.GetChars()); } - - tcall->Call = new FxVMFunctionCall(FindGlobalActionFunction("A_CallSpecial"), args, sc); - return true; + return new FxVMFunctionCall(FindGlobalActionFunction("A_CallSpecial"), args, sc); } - return false; + return NULL; } //========================================================================== @@ -319,7 +317,8 @@ do_stop: // Make the action name lowercase strlwr (sc.String); - if (DoActionSpecials(sc, state, bag, tcall)) + tcall->Call = DoActionSpecials(sc, state, bag); + if (tcall->Call != NULL) { goto endofstate; } From 00274c5e4c0bf8f2c1ab788210be0989b5495ef4 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@users.noreply.github.com> Date: Tue, 6 Jan 2015 20:02:22 -0600 Subject: [PATCH 202/232] Split action parsing out of ParseStates() and into ParseAction() --- src/thingdef/thingdef.h | 1 + src/thingdef/thingdef_states.cpp | 59 ++++++++++++++++++-------------- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index de8d524a1..70da997e3 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -189,6 +189,7 @@ AFuncDesc *FindFunction(const char * string); void ParseStates(FScanner &sc, PClassActor *actor, AActor *defaults, Baggage &bag); void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray<FxExpression *> &out_params, PFunction *afd, FString statestring, FStateDefinitions *statedef); +bool ParseAction(FScanner &sc, FState state, FString statestring, FStateTempCall *tcall, Baggage &bag); PFunction *FindGlobalActionFunction(const char *name); diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index 2d676b642..aab66f4ed 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -314,34 +314,10 @@ do_stop: continue; } - // Make the action name lowercase - strlwr (sc.String); - - tcall->Call = DoActionSpecials(sc, state, bag); - if (tcall->Call != NULL) + if (ParseAction(sc, state, statestring, tcall, bag)) { goto endofstate; } - - PFunction *afd = dyn_cast<PFunction>(bag.Info->Symbols.FindSymbol(FName(sc.String, true), true)); - if (afd != NULL) - { - // When creating the FxVMFunctionCall, we only pass args if there are any. - // So if the previous call had no args, then we can use the argument list - // allocated for it. Otherwise, we need to create a new one. - if (args == NULL) - { - args = new FArgumentList; - } - ParseFunctionParameters(sc, bag.Info, *args, afd, statestring, &bag.statedef); - tcall->Call = new FxVMFunctionCall(afd, args->Size() > 0 ? args : NULL, sc); - if (args->Size() > 0) - { - args = NULL; - } - goto endofstate; - } - sc.ScriptError("Invalid state parameter %s\n", sc.String); } sc.UnGet(); endofstate: @@ -372,6 +348,39 @@ endofstate: sc.SetEscape(true); // re-enable escape sequences } +//========================================================================== +// +// ParseAction +// +//========================================================================== + +bool ParseAction(FScanner &sc, FState state, FString statestring, FStateTempCall *tcall, Baggage &bag) +{ + // Make the action name lowercase + strlwr (sc.String); + + tcall->Call = DoActionSpecials(sc, state, bag); + if (tcall->Call != NULL) + { + return true; + } + + PFunction *afd = dyn_cast<PFunction>(bag.Info->Symbols.FindSymbol(FName(sc.String, true), true)); + if (afd != NULL) + { + FArgumentList *args = new FArgumentList; + ParseFunctionParameters(sc, bag.Info, *args, afd, statestring, &bag.statedef); + tcall->Call = new FxVMFunctionCall(afd, args->Size() > 0 ? args : NULL, sc); + if (args->Size() == 0) + { + delete args; + } + return true; + } + sc.ScriptError("Invalid state parameter %s\n", sc.String); + return false; +} + //========================================================================== // // ParseFunctionParameters From 9044ac9503bed6cc6ae3da83302ea85d799cb12a Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@users.noreply.github.com> Date: Wed, 7 Jan 2015 22:31:48 -0600 Subject: [PATCH 203/232] Don't free non-registers. - Fixed: ExpEmit::Free() would try to free REGT_NIL registers, which don't really exist --- src/thingdef/thingdef_expression.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index af6f7b52a..1f704a1a4 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -96,7 +96,7 @@ ExpEmit::ExpEmit(VMFunctionBuilder *build, int type) void ExpEmit::Free(VMFunctionBuilder *build) { - if (!Fixed && !Konst) + if (!Fixed && !Konst && RegType <= REGT_TYPE) { build->Registers[RegType].Return(RegNum, 1); } From 7d0faa5bd5f39f1b5c721e8287f94dc04811a355 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@users.noreply.github.com> Date: Wed, 7 Jan 2015 22:32:58 -0600 Subject: [PATCH 204/232] Allow multiple actions per frame - You can now call several actions from one frame by grouping them between curly braces. i.e. : POSS G 3 { A_Pain; A_Log("Ow! That hurt!"); } I will probably add an `if (something) { blah; blah; } else { wah; wah; }` construct later, but that's the extent of the munging I plan for DECORATE. The real work goes to the scripting language, not here. But if this branch is getting merged to master sooner than later, here's an immediate benefit from it right now. --- src/thingdef/thingdef.cpp | 22 +++--- src/thingdef/thingdef.h | 7 +- src/thingdef/thingdef_exp.h | 78 +++++++++++++------ src/thingdef/thingdef_expression.cpp | 108 ++++++++++++++++++++++++--- src/thingdef/thingdef_states.cpp | 52 ++++++++++--- 5 files changed, 209 insertions(+), 58 deletions(-) diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index a1350086b..d1c76943a 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -289,17 +289,15 @@ static void FinishThingdef() FStateTempCall *tcall = StateTempCalls[i]; VMFunction *func; - assert(tcall->Call != NULL); - if (tcall->Call->GetArgCount() == 0) - { - // There are no arguments, so we can call this function directly - // without wrapping it in an anonymous function. - func = tcall->Call->GetVMFunction(); - } - else + assert(tcall->Code != NULL); + + // Can we call this function directly without wrapping it in an + // anonymous function? e.g. Are we passing any parameters to it? + func = tcall->Code->GetDirectFunction(); + if (func == NULL) { FCompileContext ctx(tcall->ActorClass); - tcall->Call->Resolve(ctx); + tcall->Code->Resolve(ctx); VMFunctionBuilder buildit; // Allocate registers used to pass parameters in. @@ -307,7 +305,7 @@ static void FinishThingdef() buildit.Registers[REGT_POINTER].Get(3); // Emit a tail call via FxVMFunctionCall - tcall->Call->Emit(&buildit, true); + tcall->Code->Emit(&buildit, true); VMScriptFunction *sfunc = buildit.MakeFunction(); sfunc->NumArgs = NAP; @@ -322,8 +320,8 @@ static void FinishThingdef() codesize += sfunc->CodeSize; } } - delete tcall->Call; - tcall->Call = NULL; + delete tcall->Code; + tcall->Code = NULL; for (int k = 0; k < tcall->NumStates; ++k) { tcall->ActorClass->OwnedStates[tcall->FirstState + k].SetAction(func); diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index 70da997e3..ecec26775 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -119,10 +119,10 @@ public: struct FStateTempCall { - FStateTempCall() : ActorClass(NULL), Call(NULL), FirstState(0), NumStates(0) {} + FStateTempCall() : ActorClass(NULL), Code(NULL), FirstState(0), NumStates(0) {} PClassActor *ActorClass; - class FxVMFunctionCall *Call; + class FxTailable *Code; int FirstState; int NumStates; }; @@ -189,7 +189,8 @@ AFuncDesc *FindFunction(const char * string); void ParseStates(FScanner &sc, PClassActor *actor, AActor *defaults, Baggage &bag); void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray<FxExpression *> &out_params, PFunction *afd, FString statestring, FStateDefinitions *statedef); -bool ParseAction(FScanner &sc, FState state, FString statestring, FStateTempCall *tcall, Baggage &bag); +void ParseActions(FScanner &sc, FState state, FString statestring, FStateTempCall *tcall, Baggage &bag); +class FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, Baggage &bag); PFunction *FindGlobalActionFunction(const char *name); diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 8608557ef..47cda7c46 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -782,28 +782,6 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; -//========================================================================== -// -// FxVMFunctionCall -// -//========================================================================== - -class FxVMFunctionCall : public FxExpression -{ - PFunction *Function; - FArgumentList *ArgList; - PType *ReturnType; - -public: - FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos); - ~FxVMFunctionCall(); - FxExpression *Resolve(FCompileContext&); - virtual ExpEmit Emit(VMFunctionBuilder *build); - ExpEmit Emit(VMFunctionBuilder *build, bool tailcall); - unsigned GetArgCount() { return ArgList == NULL ? 0 : ArgList->Size(); } - VMFunction *GetVMFunction() { return Function->Variants[0].Implementation; } -}; - //========================================================================== // // FxGlobalFunctionCall @@ -823,6 +801,62 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxTailable +// +// An expression that can produce a tail call +// +//========================================================================== + +class FxTailable : public FxExpression +{ +public: + FxTailable(const FScriptPosition &pos) : FxExpression(pos) {} + virtual ExpEmit Emit(VMFunctionBuilder *build, bool tailcall) = 0; + ExpEmit Emit(VMFunctionBuilder *build); + virtual VMFunction *GetDirectFunction(); +}; + +//========================================================================== +// +// FxVMFunctionCall +// +//========================================================================== + +class FxVMFunctionCall : public FxTailable +{ + PFunction *Function; + FArgumentList *ArgList; + PType *ReturnType; + +public: + FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos); + ~FxVMFunctionCall(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build, bool tailcall); + unsigned GetArgCount() { return ArgList == NULL ? 0 : ArgList->Size(); } + VMFunction *GetVMFunction() { return Function->Variants[0].Implementation; } + VMFunction *GetDirectFunction(); +}; + +//========================================================================== +// +// FxSequence +// +//========================================================================== + +class FxSequence : public FxTailable +{ + TDeletingArray<FxTailable *> Expressions; + +public: + FxSequence(const FScriptPosition &pos) : FxTailable(pos) {} + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build, bool tailcall); + void Add(FxTailable *expr) { Expressions.Push(expr); } + VMFunction *GetDirectFunction(); +}; //========================================================================== // diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 1f704a1a4..c219c92da 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3004,6 +3004,28 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) return dest; } +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxTailable::Emit(VMFunctionBuilder *build) +{ + return Emit(build, false); +} + +//========================================================================== +// +// +// +//========================================================================== + +VMFunction *FxTailable::GetDirectFunction() +{ + return NULL; +} + //========================================================================== // // FxVMFunctionCall @@ -3011,7 +3033,7 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) //========================================================================== FxVMFunctionCall::FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos) -: FxExpression(pos) +: FxTailable(pos) { Function = func; ArgList = args; @@ -3082,15 +3104,10 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) // //========================================================================== -ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) -{ - return Emit(build, false); -} - ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall) { assert(build->Registers[REGT_POINTER].GetMostUsed() >= 3); - int count = ArgList->Size(); + int count = GetArgCount(); // Emit code to pass implied parameters if (Function->Flags & VARF_Method) @@ -3105,9 +3122,12 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall) count += 2; } // Emit code to pass explicit parameters - for (unsigned i = 0; i < ArgList->Size(); ++i) + if (ArgList != NULL) { - (*ArgList)[i]->Emit(build); + for (unsigned i = 0; i < ArgList->Size(); ++i) + { + (*ArgList)[i]->Emit(build); + } } // Get a constant register for this function int funcaddr = build->GetConstantAddress(Function->Variants[0].Implementation, ATAG_OBJECT); @@ -3132,6 +3152,24 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall) } } +//========================================================================== +// +// FxVMFunctionCall :: GetDirectFunction +// +// If the function is not passed any explicit arguments, returns the +// function. Otherwise returns NULL. +// +//========================================================================== + +VMFunction *FxVMFunctionCall::GetDirectFunction() +{ + if (GetArgCount() == 0) + { + return GetVMFunction(); + } + return NULL; +} + //========================================================================== // // @@ -3221,6 +3259,58 @@ ExpEmit FxGlobalFunctionCall::Emit(VMFunctionBuilder *build) return v; } +//========================================================================== +// +// FxSequence :: Resolve +// +//========================================================================== + +FxExpression *FxSequence::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + for (unsigned i = 0; i < Expressions.Size(); ++i) + { + if (NULL == (Expressions[i] = static_cast<FxTailable *>(Expressions[i]->Resolve(ctx)))) + { + delete this; + return NULL; + } + } + return this; +} + +//========================================================================== +// +// FxSequence :: Emit +// +//========================================================================== + +ExpEmit FxSequence::Emit(VMFunctionBuilder *build, bool tailcall) +{ + for (unsigned i = 0; i < Expressions.Size(); ++i) + { + ExpEmit v = Expressions[i]->Emit(build, tailcall ? i == Expressions.Size()-1 : false); + // Throw away any result. We don't care about it. + v.Free(build); + } + return ExpEmit(); +} + +//========================================================================== +// +// FxSequence :: GetDirectFunction +// +//========================================================================== + +VMFunction *FxSequence::GetDirectFunction() +{ + if (Expressions.Size() == 1) + { + return Expressions[0]->GetDirectFunction(); + } + return NULL; +} + //========================================================================== // //========================================================================== diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index aab66f4ed..94f5de1bc 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -314,10 +314,8 @@ do_stop: continue; } - if (ParseAction(sc, state, statestring, tcall, bag)) - { - goto endofstate; - } + ParseActions(sc, state, statestring, tcall, bag); + goto endofstate; } sc.UnGet(); endofstate: @@ -327,7 +325,7 @@ endofstate: sc.ScriptError ("Invalid frame character string '%s'", statestring.GetChars()); count = -count; } - if (tcall->Call != NULL) + if (tcall->Code != NULL) { tcall->ActorClass = actor; tcall->FirstState = bag.statedef.GetStateCount() - count; @@ -348,21 +346,51 @@ endofstate: sc.SetEscape(true); // re-enable escape sequences } +//========================================================================== +// +// ParseActions +// +//========================================================================== + +void ParseActions(FScanner &sc, FState state, FString statestring, FStateTempCall *tcall, Baggage &bag) +{ + // If it's not a '{', then it should be a single action. + // Otherwise, it's a sequence of actions. + if (!sc.Compare("{")) + { + tcall->Code = ParseAction(sc, state, statestring, bag); + return; + } + + FxSequence *seq = new FxSequence(sc); + sc.MustGetString(); + while (!sc.Compare("}")) + { + FxVMFunctionCall *call = ParseAction(sc, state, statestring, bag); + seq->Add(call); + sc.MustGetStringName(";"); + sc.MustGetString(); + } + tcall->Code = seq; +} + //========================================================================== // // ParseAction // //========================================================================== -bool ParseAction(FScanner &sc, FState state, FString statestring, FStateTempCall *tcall, Baggage &bag) +FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, Baggage &bag) { + FxVMFunctionCall *call; + // Make the action name lowercase strlwr (sc.String); - tcall->Call = DoActionSpecials(sc, state, bag); - if (tcall->Call != NULL) + call = DoActionSpecials(sc, state, bag); + if (call != NULL) { - return true; + return call; } PFunction *afd = dyn_cast<PFunction>(bag.Info->Symbols.FindSymbol(FName(sc.String, true), true)); @@ -370,15 +398,15 @@ bool ParseAction(FScanner &sc, FState state, FString statestring, FStateTempCall { FArgumentList *args = new FArgumentList; ParseFunctionParameters(sc, bag.Info, *args, afd, statestring, &bag.statedef); - tcall->Call = new FxVMFunctionCall(afd, args->Size() > 0 ? args : NULL, sc); + call = new FxVMFunctionCall(afd, args->Size() > 0 ? args : NULL, sc); if (args->Size() == 0) { delete args; } - return true; + return call; } sc.ScriptError("Invalid state parameter %s\n", sc.String); - return false; + return NULL; } //========================================================================== From 649875b17e78a504880e9c8914c512b527b5f224 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@users.noreply.github.com> Date: Thu, 8 Jan 2015 21:36:42 -0600 Subject: [PATCH 205/232] Add if/else blocks for action sequences - So now you can do something like this for an action: { if (health > 1000) { A_Scream; } else { A_XScream; } } Yes, the braces are required. Because I see too many instances where somebody writes an if statement in ACS and doesn't understand why it doesn't work right because they forgot braces. - Fixed: Not actually putting an action between { and } would crash. --- src/thingdef/thingdef.cpp | 54 +++++++------ src/thingdef/thingdef.h | 2 +- src/thingdef/thingdef_exp.h | 21 ++++- src/thingdef/thingdef_expression.cpp | 114 +++++++++++++++++++++++++++ src/thingdef/thingdef_states.cpp | 51 +++++++++--- 5 files changed, 207 insertions(+), 35 deletions(-) diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index d1c76943a..60a0da8de 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -297,34 +297,42 @@ static void FinishThingdef() if (func == NULL) { FCompileContext ctx(tcall->ActorClass); - tcall->Code->Resolve(ctx); - VMFunctionBuilder buildit; + tcall->Code = static_cast<FxTailable *>(tcall->Code->Resolve(ctx)); - // Allocate registers used to pass parameters in. - // self, stateowner, state (all are pointers) - buildit.Registers[REGT_POINTER].Get(3); - - // Emit a tail call via FxVMFunctionCall - tcall->Code->Emit(&buildit, true); - - VMScriptFunction *sfunc = buildit.MakeFunction(); - sfunc->NumArgs = NAP; - func = sfunc; - - if (dump != NULL) + // Make sure resolving it didn't obliterate it. + if (tcall->Code != NULL) { - char label[64]; - int labellen = mysnprintf(label, countof(label), "Function %s.States[%d] (*%d)", - tcall->ActorClass->TypeName.GetChars(), tcall->FirstState, tcall->NumStates); - DumpFunction(dump, sfunc, label, labellen); - codesize += sfunc->CodeSize; + VMFunctionBuilder buildit; + + // Allocate registers used to pass parameters in. + // self, stateowner, state (all are pointers) + buildit.Registers[REGT_POINTER].Get(3); + + // Emit a tail call via FxVMFunctionCall + tcall->Code->Emit(&buildit, true); + + VMScriptFunction *sfunc = buildit.MakeFunction(); + sfunc->NumArgs = NAP; + func = sfunc; + + if (dump != NULL) + { + char label[64]; + int labellen = mysnprintf(label, countof(label), "Function %s.States[%d] (*%d)", + tcall->ActorClass->TypeName.GetChars(), tcall->FirstState, tcall->NumStates); + DumpFunction(dump, sfunc, label, labellen); + codesize += sfunc->CodeSize; + } } } - delete tcall->Code; - tcall->Code = NULL; - for (int k = 0; k < tcall->NumStates; ++k) + if (tcall->Code != NULL) { - tcall->ActorClass->OwnedStates[tcall->FirstState + k].SetAction(func); + delete tcall->Code; + tcall->Code = NULL; + for (int k = 0; k < tcall->NumStates; ++k) + { + tcall->ActorClass->OwnedStates[tcall->FirstState + k].SetAction(func); + } } } diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index ecec26775..9eb6d2677 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -189,7 +189,7 @@ AFuncDesc *FindFunction(const char * string); void ParseStates(FScanner &sc, PClassActor *actor, AActor *defaults, Baggage &bag); void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray<FxExpression *> &out_params, PFunction *afd, FString statestring, FStateDefinitions *statedef); -void ParseActions(FScanner &sc, FState state, FString statestring, FStateTempCall *tcall, Baggage &bag); +FxTailable *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag); class FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, Baggage &bag); PFunction *FindGlobalActionFunction(const char *name); diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 47cda7c46..7f8bad6ea 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -854,10 +854,29 @@ public: FxSequence(const FScriptPosition &pos) : FxTailable(pos) {} FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build, bool tailcall); - void Add(FxTailable *expr) { Expressions.Push(expr); } + void Add(FxTailable *expr) { if (expr != NULL) Expressions.Push(expr); } VMFunction *GetDirectFunction(); }; +//========================================================================== +// +// FxIfStatement +// +//========================================================================== + +class FxIfStatement : public FxTailable +{ + FxExpression *Condition; + FxTailable *WhenTrue; + FxTailable *WhenFalse; + +public: + FxIfStatement(FxExpression *cond, FxTailable *true_part, FxTailable *false_part, const FScriptPosition &pos); + ~FxIfStatement(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build, bool tailcall); +}; + //========================================================================== // // diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index c219c92da..eb8256778 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3311,6 +3311,120 @@ VMFunction *FxSequence::GetDirectFunction() return NULL; } +//========================================================================== +// +// FxIfStatement +// +//========================================================================== + +FxIfStatement::FxIfStatement(FxExpression *cond, FxTailable *true_part, + FxTailable *false_part, const FScriptPosition &pos) +: FxTailable(pos) +{ + Condition = cond; + WhenTrue = true_part; + WhenFalse = false_part; + assert(cond != NULL); +} + +FxIfStatement::~FxIfStatement() +{ + SAFE_DELETE(Condition); + SAFE_DELETE(WhenTrue); + SAFE_DELETE(WhenFalse); +} + +FxExpression *FxIfStatement::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + if (WhenTrue == NULL && WhenFalse == NULL) + { // We don't do anything either way, so disappear + delete this; + return NULL; + } + Condition = Condition->ResolveAsBoolean(ctx); + ABORT(Condition); + if (WhenTrue != NULL) + { + WhenTrue = static_cast<FxTailable *>(WhenTrue->Resolve(ctx)); + ABORT(WhenTrue); + } + if (WhenFalse != NULL) + { + WhenFalse = static_cast<FxTailable *>(WhenFalse->Resolve(ctx)); + ABORT(WhenFalse); + } + ValueType = VAL_Unknown; + + if (Condition->isConstant()) + { + ExpVal condval = static_cast<FxConstant *>(Condition)->GetValue(); + bool result = condval.GetBool(); + + FxTailable *e = result ? WhenTrue : WhenFalse; + delete (result ? WhenFalse : WhenTrue); + WhenTrue = WhenFalse = NULL; + delete this; + return e; + } + return this; +} + +ExpEmit FxIfStatement::Emit(VMFunctionBuilder *build, bool tailcall) +{ + ExpEmit v; + size_t jumpspot; + FxTailable *path1, *path2; + int condcheck; + + // This is pretty much copied from FxConditional, except we don't + // keep any results. + ExpEmit cond = Condition->Emit(build); + assert(cond.RegType == REGT_INT && !cond.Konst); + + if (WhenTrue != NULL) + { + path1 = WhenTrue; + path2 = WhenFalse; + condcheck = 1; + } + else + { + // When there is only a false path, reverse the condition so we can + // treat it as a true path. + assert(WhenFalse != NULL); + path1 = WhenFalse; + path2 = NULL; + condcheck = 0; + } + + // Test condition. + build->Emit(OP_EQ_K, condcheck, cond.RegNum, build->GetConstantInt(0)); + jumpspot = build->Emit(OP_JMP, 0); + cond.Free(build); + + // Evaluate first path + v = path1->Emit(build, tailcall); + v.Free(build); + if (path2 != NULL) + { + size_t path1jump = build->Emit(OP_JMP, 0); + // Evaluate second path + build->BackpatchToHere(jumpspot); + v = path2->Emit(build, tailcall); + v.Free(build); + jumpspot = path1jump; + } + build->BackpatchToHere(jumpspot); + if (tailcall) + { + // When tailcall is true, execution is not expected to get past + // this if statement, so issue a RET. + build->Emit(OP_RET, RET_FINAL, REGT_NIL, 0); + } + return ExpEmit(); +} + //========================================================================== // //========================================================================== diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index 94f5de1bc..fedfd924e 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -314,7 +314,7 @@ do_stop: continue; } - ParseActions(sc, state, statestring, tcall, bag); + tcall->Code = ParseActions(sc, state, statestring, bag); goto endofstate; } sc.UnGet(); @@ -352,26 +352,57 @@ endofstate: // //========================================================================== -void ParseActions(FScanner &sc, FState state, FString statestring, FStateTempCall *tcall, Baggage &bag) +FxTailable *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag) { // If it's not a '{', then it should be a single action. // Otherwise, it's a sequence of actions. if (!sc.Compare("{")) { - tcall->Code = ParseAction(sc, state, statestring, bag); - return; + return ParseAction(sc, state, statestring, bag); } - FxSequence *seq = new FxSequence(sc); + const FScriptPosition pos(sc); + + FxSequence *seq = NULL; sc.MustGetString(); while (!sc.Compare("}")) { - FxVMFunctionCall *call = ParseAction(sc, state, statestring, bag); - seq->Add(call); - sc.MustGetStringName(";"); - sc.MustGetString(); + FxTailable *add; + if (sc.Compare("if")) + { // Hangle an if statement + FxExpression *cond; + FxTailable *true_part, *false_part = NULL; + sc.MustGetStringName("("); + cond = ParseExpression(sc, bag.Info); + sc.MustGetStringName(")"); + sc.MustGetStringName("{"); // braces are mandatory + true_part = ParseActions(sc, state, statestring, bag); + sc.MustGetString(); + if (sc.Compare("else")) + { + sc.MustGetStringName("{"); // braces are still mandatory + false_part = ParseActions(sc, state, statestring, bag); + sc.MustGetString(); + } + add = new FxIfStatement(cond, true_part, false_part, sc); + } + else + { // Handle a regular action function call + add = ParseAction(sc, state, statestring, bag); + sc.MustGetStringName(";"); + sc.MustGetString(); + } + // Only return a sequence if it has actual content. + if (add != NULL) + { + if (seq == NULL) + { + seq = new FxSequence(pos); + } + seq->Add(add); + } } - tcall->Code = seq; + return seq; } //========================================================================== From 9b81e0e5971625b1d6fde5cc5c5812d98d567ec6 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@users.noreply.github.com> Date: Sat, 10 Jan 2015 23:00:45 -0600 Subject: [PATCH 206/232] 16-byte align frames on the VMFrameStack - Fixed: Don't assume operator new will return a pointer with 16-byte alignment when allocating a block for the VMFrameStack. Because it seems it's actually guaranteed to be 8-byte aligned. Don't know where I got the idea it would always be 16-byte aligned. --- src/zscript/vm.h | 6 ++++++ src/zscript/vmframe.cpp | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/zscript/vm.h b/src/zscript/vm.h index d3e4580ce..4bc8f01c0 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -682,6 +682,7 @@ struct VMFrame VMValue *GetParam() const { + assert(((size_t)this & 15) == 0 && "VM frame is unaligned"); return (VMValue *)(((size_t)(this + 1) + 15) & ~15); } @@ -789,6 +790,11 @@ private: VMFrame *LastFrame; VM_UBYTE *FreeSpace; int BlockSize; + + void InitFreeSpace() + { + FreeSpace = (VM_UBYTE *)(((size_t)(this + 1) + 15) & ~15); + } }; BlockHeader *Blocks; BlockHeader *UnusedBlocks; diff --git a/src/zscript/vmframe.cpp b/src/zscript/vmframe.cpp index 0c2cacfc2..82affc053 100644 --- a/src/zscript/vmframe.cpp +++ b/src/zscript/vmframe.cpp @@ -286,7 +286,7 @@ VMFrame *VMFrameStack::Alloc(int size) block = (BlockHeader *)new VM_UBYTE[blocksize]; block->BlockSize = blocksize; } - block->FreeSpace = (VM_UBYTE *)block + ((sizeof(BlockHeader) + 15) & ~15); + block->InitFreeSpace(); block->LastFrame = NULL; block->NextBlock = Blocks; Blocks = block; @@ -340,7 +340,7 @@ VMFrame *VMFrameStack::PopFrame() { assert(Blocks->NextBlock == NULL); Blocks->LastFrame = NULL; - Blocks->FreeSpace = (VM_UBYTE *)Blocks + ((sizeof(BlockHeader) + 15) & ~15); + Blocks->InitFreeSpace(); } return NULL; } From bd3e49c0e844c1ae03b3c315902b984b8fe75776 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@users.noreply.github.com> Date: Sat, 10 Jan 2015 23:02:00 -0600 Subject: [PATCH 207/232] Make actor damages readable from DECORATE (again) --- src/namedef.h | 1 + src/thingdef/thingdef_exp.h | 14 ++++++ src/thingdef/thingdef_expression.cpp | 65 ++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) diff --git a/src/namedef.h b/src/namedef.h index 17626092a..661c8be19 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -610,6 +610,7 @@ xx(DecoCallLineSpecial) xx(DecoNameToClass) xx(DecoFindMultiNameState) xx(DecoFindSingleNameState) +xx(Damage) // basic type names xx(Default) diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 7f8bad6ea..fab33a95b 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -719,6 +719,20 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxDamage +// +//========================================================================== + +class FxDamage : public FxExpression +{ +public: + FxDamage(const FScriptPosition&); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxArrayElement diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index eb8256778..148df60e7 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -2424,6 +2424,11 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) ScriptPosition.Message(MSG_ERROR, "Invalid member identifier '%s'\n", Identifier.GetChars()); } } + // the damage property needs special handling + else if (Identifier == NAME_Damage) + { + newex = new FxDamage(ScriptPosition); + } // now check the global identifiers. else if ((sym = ctx.FindGlobal(Identifier)) != NULL) { @@ -2516,6 +2521,66 @@ ExpEmit FxSelf::Emit(VMFunctionBuilder *build) return me; } + +//========================================================================== +// +// +// +//========================================================================== + +FxDamage::FxDamage(const FScriptPosition &pos) +: FxExpression(pos) +{ +} + +//========================================================================== +// +// FxDamage :: Resolve +// +//========================================================================== + +FxExpression *FxDamage::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + ValueType = VAL_Int; + return this; +} + +//========================================================================== +// +// FxDamage :: Emit +// +// Call this actor's damage function, if it has one +// +//========================================================================== + +ExpEmit FxDamage::Emit(VMFunctionBuilder *build) +{ + ExpEmit dmgval(build, REGT_INT); + + // Get damage function + ExpEmit dmgfunc(build, REGT_POINTER); + build->Emit(OP_LO, dmgfunc.RegNum, 0/*self*/, build->GetConstantInt(myoffsetof(AActor, Damage))); + + // If it's non-null... + build->Emit(OP_EQA_K, 1, dmgfunc.RegNum, build->GetConstantAddress(0, ATAG_GENERIC)); + size_t nulljump = build->Emit(OP_JMP, 0); + + // ...call it + build->Emit(OP_PARAM, 0, REGT_POINTER, 0/*self*/); + build->Emit(OP_CALL, dmgfunc.RegNum, 1, 1); + build->Emit(OP_RESULT, 0, REGT_INT, dmgval.RegNum); + size_t notnulljump = build->Emit(OP_JMP, 0); + + // Otherwise, use 0 + build->BackpatchToHere(nulljump); + build->EmitLoadInt(dmgval.RegNum, 0); + build->BackpatchToHere(notnulljump); + + return dmgval; +} + + //========================================================================== // // From 5d2cbf4ecb1752f0cf10b39bee21c1921a3682f1 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@users.noreply.github.com> Date: Fri, 13 Mar 2015 23:14:42 -0500 Subject: [PATCH 208/232] Improve disassembly of branch instructions - I kept getting confused trying to read these instructions, so now their disassembly looks more MIPS-like: * All mnemonics have had 'b' prepended to them for "branch". * The CMP_CHECK bit alters the displayed mnemonic for the inverted versions. e.g. BEQ can be displayed as BNE. * The following JMP instruction that encodes the branch destination has been folded into the disassembly of the branch instruction. Unlike MIPS, I chose to display it offset from the branch check with => instead of another comma. --- src/zscript/vm.h | 2 ++ src/zscript/vmdisasm.cpp | 65 +++++++++++++++++++++++++++++++++++----- src/zscript/vmops.h | 52 ++++++++++++++++---------------- 3 files changed, 85 insertions(+), 34 deletions(-) diff --git a/src/zscript/vm.h b/src/zscript/vm.h index 4bc8f01c0..06f289bb4 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -193,6 +193,7 @@ enum EVMOpMode MODE_IMMS, MODE_IMMZ, MODE_JOINT, + MODE_CMP, MODE_PARAM, MODE_THROW, @@ -209,6 +210,7 @@ enum EVMOpMode MODE_AUNUSED = MODE_UNUSED << MODE_ASHIFT, MODE_AIMMS = MODE_IMMS << MODE_ASHIFT, MODE_AIMMZ = MODE_IMMZ << MODE_ASHIFT, + MODE_ACMP = MODE_CMP << MODE_ASHIFT, MODE_BI = MODE_I << MODE_BSHIFT, MODE_BF = MODE_F << MODE_BSHIFT, diff --git a/src/zscript/vmdisasm.cpp b/src/zscript/vmdisasm.cpp index e003d1595..2509b60a9 100644 --- a/src/zscript/vmdisasm.cpp +++ b/src/zscript/vmdisasm.cpp @@ -93,6 +93,17 @@ #define I8RPRP MODE_AIMMZ | MODE_BP | MODE_CP #define I8RPKP MODE_AIMMZ | MODE_BP | MODE_CKP +#define CIRR MODE_ACMP | MODE_BI | MODE_CI +#define CIRK MODE_ACMP | MODE_BI | MODE_CKI +#define CIKR MODE_ACMP | MODE_BKI | MODE_CI +#define CFRR MODE_ACMP | MODE_BF | MODE_CF +#define CFRK MODE_ACMP | MODE_BF | MODE_CKF +#define CFKR MODE_ACMP | MODE_BKF | MODE_CF +#define CVRR MODE_ACMP | MODE_BV | MODE_CV +#define CVRK MODE_ACMP | MODE_BV | MODE_CKV +#define CPRR MODE_ACMP | MODE_BP | MODE_CP +#define CPRK MODE_ACMP | MODE_BP | MODE_CKP + const VMOpInfo OpInfo[NUM_OPS] = { #define xx(op, name, mode) { #name, mode } @@ -214,28 +225,51 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction int col; int mode; int a; + bool cmp; + char cmpname[8]; for (int i = 0; i < codesize; ++i) { name = OpInfo[code[i].op].Name; mode = OpInfo[code[i].op].Mode; a = code[i].a; + cmp = (mode & MODE_ATYPE) == MODE_ACMP; // String comparison encodes everything in a single instruction. if (code[i].op == OP_CMPS) { switch (a & CMP_METHOD_MASK) { - case CMP_EQ: name = "eq"; break; - case CMP_LT: name = "lt"; break; - case CMP_LE: name = "le"; break; + case CMP_EQ: name = "beq"; break; + case CMP_LT: name = "blt"; break; + case CMP_LE: name = "ble"; break; } mode = MODE_AIMMZ; mode |= (a & CMP_BK) ? MODE_BKS : MODE_BS; mode |= (a & CMP_CK) ? MODE_CKS : MODE_CS; a &= CMP_CHECK | CMP_APPROX; + cmp = true; + } + if (cmp) + { // Comparison instruction. Modify name for inverted test. + if (!(a & CMP_CHECK)) + { + strcpy(cmpname, name); + if (name[1] == 'e') + { // eq -> ne + cmpname[1] = 'n', cmpname[2] = 'e'; + } + else if (name[2] == 't') + { // lt -> ge + cmpname[1] = 'g', cmpname[2] = 'e'; + } + else + { // le -> gt + cmpname[1] = 'g', cmpname[2] = 't'; + } + name = cmpname; + } } - printf_wrapper(out, "%08x: %02x%02x%02x%02x %-8s", i << 2, code[i].op, code[i].a, code[i].b, code[i].c, name); col = 0; switch (code[i].op) @@ -299,7 +333,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction col = printf_wrapper(out, "f%d,f%d,%d", code[i].a, code[i].b, code[i].c); if (code[i].c < countof(FlopNames)) { - col +=printf_wrapper(out, " [%s]", FlopNames[code[i].c]); + col += printf_wrapper(out, " [%s]", FlopNames[code[i].c]); } break; @@ -371,19 +405,34 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction } break; } + if (cmp && i + 1 < codesize) + { + if (code[i+1].op != OP_JMP) + { // comparison instructions must be followed by jump + col += printf_wrapper(out, " => *!*!*!*\n"); + } + else + { + col += printf_wrapper(out, " => %08x", (i + 2 + code[i+1].i24) << 2); + } + } if (col > 30) { col = 30; } printf_wrapper(out, "%*c", 30 - col, ';'); - if (code[i].op == OP_JMP || code[i].op == OP_TRY || code[i].op == OP_PARAMI) + if (!cmp && (code[i].op == OP_JMP || code[i].op == OP_TRY || code[i].op == OP_PARAMI)) { printf_wrapper(out, "%d\n", code[i].i24); } else { printf_wrapper(out, "%d,%d,%d", code[i].a, code[i].b, code[i].c); - if (code[i].op == OP_CALL_K || code[i].op == OP_TAIL_K) + if (cmp && i + 1 < codesize && code[i+1].op == OP_JMP) + { + printf_wrapper(out, ",%d\n", code[++i].i24); + } + else if (code[i].op == OP_CALL_K || code[i].op == OP_TAIL_K) { printf_wrapper(out, " [%p]\n", callfunc); } @@ -397,7 +446,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction static int print_reg(FILE *out, int col, int arg, int mode, int immshift, const VMScriptFunction *func) { - if (mode == MODE_UNUSED) + if (mode == MODE_UNUSED || mode == MODE_CMP) { return 0; } diff --git a/src/zscript/vmops.h b/src/zscript/vmops.h index 125e5463d..998a4eb0c 100644 --- a/src/zscript/vmops.h +++ b/src/zscript/vmops.h @@ -146,20 +146,20 @@ xx(ZAP_R, zap, RIRIRI), // dA = dB, with bytes zeroed where bits in C/dC are o xx(ZAP_I, zap, RIRII8), xx(ZAPNOT_R, zapnot, RIRIRI), // dA = dB, with bytes zeroed where bits in C/dC are zero xx(ZAPNOT_I, zapnot, RIRII8), -xx(EQ_R, eq, I8RIRI), // if ((dB == dkC) != A) then pc++ -xx(EQ_K, eq, I8RIKI), -xx(LT_RR, lt, I8RIRI), // if ((dkB < dkC) != A) then pc++ -xx(LT_RK, lt, I8RIKI), -xx(LT_KR, lt, I8KIRI), -xx(LE_RR, le, I8RIRI), // if ((dkB <= dkC) != A) then pc++ -xx(LE_RK, le, I8RIKI), -xx(LE_KR, le, I8KIRI), -xx(LTU_RR, ltu, I8RIRI), // if ((dkB < dkC) != A) then pc++ -- unsigned -xx(LTU_RK, ltu, I8RIKI), -xx(LTU_KR, ltu, I8KIRI), -xx(LEU_RR, leu, I8RIRI), // if ((dkB <= dkC) != A) then pc++ -- unsigned -xx(LEU_RK, leu, I8RIKI), -xx(LEU_KR, leu, I8KIRI), +xx(EQ_R, beq, CIRR), // if ((dB == dkC) != A) then pc++ +xx(EQ_K, beq, CIRK), +xx(LT_RR, blt, CIRR), // if ((dkB < dkC) != A) then pc++ +xx(LT_RK, blt, CIRK), +xx(LT_KR, blt, CIKR), +xx(LE_RR, ble, CIRR), // if ((dkB <= dkC) != A) then pc++ +xx(LE_RK, ble, CIRK), +xx(LE_KR, ble, CIKR), +xx(LTU_RR, bltu, CIRR), // if ((dkB < dkC) != A) then pc++ -- unsigned +xx(LTU_RK, bltu, CIRK), +xx(LTU_KR, bltu, CIKR), +xx(LEU_RR, bleu, CIRR), // if ((dkB <= dkC) != A) then pc++ -- unsigned +xx(LEU_RK, bleu, CIRK), +xx(LEU_KR, bleu, CIKR), // Double-precision floating point math. xx(ADDF_RR, add, RFRFRF), // fA = fB + fkC @@ -183,14 +183,14 @@ xx(MINF_RK, min, RFRFKF), xx(MAXF_RR, max, RFRFRF), // fA = max(fB),fkC) xx(MAXF_RK, max, RFRFKF), xx(FLOP, flop, RFRFI8), // fA = f(fB), where function is selected by C -xx(EQF_R, eq, I8RFRF), // if ((fB == fkC) != (A & 1)) then pc++ -xx(EQF_K, eq, I8RFKF), -xx(LTF_RR, lt, I8RFRF), // if ((fkB < fkC) != (A & 1)) then pc++ -xx(LTF_RK, lt, I8RFKF), -xx(LTF_KR, lt, I8KFRF), -xx(LEF_RR, le, I8RFRF), // if ((fkb <= fkC) != (A & 1)) then pc++ -xx(LEF_RK, le, I8RFKF), -xx(LEF_KR, le, I8KFRF), +xx(EQF_R, beq, CFRR), // if ((fB == fkC) != (A & 1)) then pc++ +xx(EQF_K, beq, CFRK), +xx(LTF_RR, blt, CFRR), // if ((fkB < fkC) != (A & 1)) then pc++ +xx(LTF_RK, blt, CFRK), +xx(LTF_KR, blt, CFKR), +xx(LEF_RR, ble, CFRR), // if ((fkb <= fkC) != (A & 1)) then pc++ +xx(LEF_RK, ble, CFRK), +xx(LEF_KR, ble, CFKR), // Vector math. xx(NEGV, negv, RVRV), // vA = -vB @@ -208,14 +208,14 @@ xx(MULVF_RR, mulv, RVRVRV), // vA = vkB * fkC xx(MULVF_RK, mulv, RVRVKV), xx(MULVF_KR, mulv, RVKVRV), xx(LENV, lenv, RFRV), // fA = vB.Length -xx(EQV_R, eqv, I8RVRV), // if ((vB == vkC) != A) then pc++ (inexact if A & 32) -xx(EQV_K, eqv, I8RVKV), +xx(EQV_R, beqv, CVRR), // if ((vB == vkC) != A) then pc++ (inexact if A & 32) +xx(EQV_K, beqv, CVRK), // Pointer math. xx(ADDA_RR, add, RPRPRI), // pA = pB + dkC xx(ADDA_RK, add, RPRPKI), xx(SUBA, sub, RIRPRP), // dA = pB - pC -xx(EQA_R, eq, I8RPRP), // if ((pB == pkC) != A) then pc++ -xx(EQA_K, eq, I8RPKP), +xx(EQA_R, beq, CPRR), // if ((pB == pkC) != A) then pc++ +xx(EQA_K, beq, CPRK), #undef xx From 1e7cce5a2c0923ea78879f82ae6d7ac665d233ff Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@users.noreply.github.com> Date: Sat, 14 Mar 2015 22:04:53 -0500 Subject: [PATCH 209/232] Add missing NewPointer() function --- src/dobjtype.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index c601e1f55..f7623f84d 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -1300,6 +1300,26 @@ void PPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const id2 = 0; } +//========================================================================== +// +// NewPointer +// +// Returns a PPointer to an object of the specified type +// +//========================================================================== + +PPointer *NewPointer(PType *type) +{ + size_t bucket; + PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PPointer), (intptr_t)type, 0, &bucket); + if (ptype == NULL) + { + ptype = new PPointer(type); + TypeTable.AddType(ptype, RUNTIME_CLASS(PPointer), (intptr_t)type, 0, bucket); + } + return static_cast<PPointer *>(ptype); +} + /* PClassPointer **********************************************************/ From 8cb269388e331d35e36194b580bb1d4014d9f81e Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@users.noreply.github.com> Date: Sat, 14 Mar 2015 22:07:52 -0500 Subject: [PATCH 210/232] Eliminate .mreg section - Member variables are now declared all in one place: InitThingdef(). They are not partially defined in thingdef_expression.cpp and further refined in actor.txt. - This left ParseNativeVariable() parsing only functions, so it has been renamed to ParseNativeFunction(). - Note that their declarations in InitThingdef() are expected to be temporary. --- src/__autostart.cpp | 6 +- src/autosegs.h | 4 -- src/dobjtype.h | 1 + src/namedef.h | 10 +++ src/thingdef/thingdef.h | 18 ------ src/thingdef/thingdef_data.cpp | 94 +++++++++++----------------- src/thingdef/thingdef_expression.cpp | 39 +----------- src/thingdef/thingdef_parse.cpp | 93 ++++++--------------------- src/zzautozend.cpp | 4 -- wadsrc/static/actors/actor.txt | 41 +----------- 10 files changed, 69 insertions(+), 241 deletions(-) diff --git a/src/__autostart.cpp b/src/__autostart.cpp index 7babed907..1b111e121 100644 --- a/src/__autostart.cpp +++ b/src/__autostart.cpp @@ -53,7 +53,7 @@ // for initialized read-only data.) #pragma comment(linker, "/merge:.areg=.rdata /merge:.creg=.rdata /merge:.greg=.rdata") -#pragma comment(linker, "/merge:.mreg=.rdata /merge:.yreg=.rdata") +#pragma comment(linker, "/merge:.yreg=.rdata") #pragma section(".areg$a",read) __declspec(allocate(".areg$a")) void *const ARegHead = 0; @@ -64,9 +64,6 @@ __declspec(allocate(".creg$a")) void *const CRegHead = 0; #pragma section(".greg$a",read) __declspec(allocate(".greg$a")) void *const GRegHead = 0; -#pragma section(".mreg$a",read) -__declspec(allocate(".mreg$a")) void *const MRegHead = 0; - #pragma section(".yreg$a",read) __declspec(allocate(".yreg$a")) void *const YRegHead = 0; @@ -101,7 +98,6 @@ __declspec(allocate(".yreg$a")) void *const YRegHead = 0; void *const ARegHead __attribute__((section(SECTION_AREG))) = 0; void *const CRegHead __attribute__((section(SECTION_CREG))) = 0; void *const GRegHead __attribute__((section(SECTION_GREG))) = 0; -void *const MRegHead __attribute__((section(SECTION_MREG))) = 0; void *const YRegHead __attribute__((section(SECTION_YREG))) = 0; #else diff --git a/src/autosegs.h b/src/autosegs.h index b4f825879..b32594d84 100644 --- a/src/autosegs.h +++ b/src/autosegs.h @@ -50,10 +50,6 @@ extern REGINFO CRegTail; extern REGINFO GRegHead; extern REGINFO GRegTail; -// List of variables -extern REGINFO MRegHead; -extern REGINFO MRegTail; - // List of MAPINFO map options extern REGINFO YRegHead; extern REGINFO YRegTail; diff --git a/src/dobjtype.h b/src/dobjtype.h index 0463eee0b..92917f7ec 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -461,6 +461,7 @@ class PField : public PSymbol public: PField(FName name, PType *type) : PSymbol(name), Offset(0), Type(type), Flags(0) {} PField(FName name, PType *type, DWORD flags) : PSymbol(name), Offset(0), Type(type), Flags(flags) {} + PField(FName name, PType *type, DWORD flags, unsigned offset) : PSymbol(name), Offset(offset), Type(type), Flags(flags) {} unsigned int Offset; PType *Type; diff --git a/src/namedef.h b/src/namedef.h index 661c8be19..d738d98c8 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -303,6 +303,16 @@ xx(Sqrt) xx(CheckClass) xx(IsPointerEqual) xx(Pick) +xx(Mass) +xx(VelX) +xx(VelY) +xx(VelZ) +xx(Accuracy) +xx(Stamina) +xx(Radius) +xx(ReactionTime) +xx(MeleeRange) +xx(Speed) // Various actor names which are used internally xx(MapSpot) diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index 9eb6d2677..d8c13174a 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -280,16 +280,7 @@ struct FPropertyInfo int category; }; -struct FVariableInfo -{ - const char *name; - intptr_t address; - const PClass * const *owner; -}; - - FPropertyInfo *FindProperty(const char * string); -FVariableInfo *FindVariable(const char * string, const PClass *cls); int MatchString (const char *in, const char **strings); @@ -335,15 +326,6 @@ int MatchString (const char *in, const char **strings); int var = params[(no)+1].i== 0? params[(no)+2].i : V_GetColor(NULL, params[(no)+2].s); -#define DEFINE_MEMBER_VARIABLE(name, cls) \ - static FVariableInfo GlobalDef__##name = { #name, static_cast<intptr_t>(myoffsetof(cls, name)), &RUNTIME_CLASS_CASTLESS(cls) }; \ - MSVC_MSEG FVariableInfo *infoptr_GlobalDef__##name GCC_MSEG = &GlobalDef__##name; - -#define DEFINE_MEMBER_VARIABLE_ALIAS(name, alias, cls) \ - static FVariableInfo GlobalDef__##name = { #name, static_cast<intptr_t>(myoffsetof(cls, alias)), &RUNTIME_CLASS_CASTLESS(cls) }; \ - MSVC_MSEG FVariableInfo *infoptr_GlobalDef__##name GCC_MSEG = &GlobalDef__##name; - - // Macros to handle action functions. These are here so that I don't have to // change every single use in case the parameters change. #define DECLARE_ACTION(name) extern VMNativeFunction *name##_VMPtr; diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 2d9b54cab..5de2dd413 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -46,7 +46,6 @@ static TArray<FPropertyInfo*> properties; static TArray<AFuncDesc> AFTable; -static TArray<FVariableInfo*> variables; //========================================================================== // @@ -533,42 +532,6 @@ AFuncDesc *FindFunction(const char * string) } -//========================================================================== -// -// Find a variable by name using a binary search -// -//========================================================================== - -FVariableInfo *FindVariable(const char * string, const PClass *cls) -{ - int min = 0, max = variables.Size()-1; - - while (min <= max) - { - int mid = (min + max) / 2; - int lexval; - - if (cls < *variables[mid]->owner) lexval = -1; - else if (cls > *variables[mid]->owner) lexval = 1; - else lexval = stricmp (string, variables[mid]->name); - - if (lexval == 0) - { - return variables[mid]; - } - else if (lexval > 0) - { - min = mid + 1; - } - else - { - max = mid - 1; - } - } - return NULL; -} - - //========================================================================== // // Find an action function in AActor's table @@ -602,15 +565,6 @@ static int STACK_ARGS funccmp(const void * a, const void * b) return stricmp( ((AFuncDesc*)a)->Name, ((AFuncDesc*)b)->Name); } -static int STACK_ARGS varcmp(const void * a, const void * b) -{ - FVariableInfo *A = *(FVariableInfo**)a; - FVariableInfo *B = *(FVariableInfo**)b; - if (A->owner < B->owner) return -1; - if (A->owner > B->owner) return 1; - return stricmp(A->name, B->name); -} - //========================================================================== // // Initialization @@ -654,17 +608,39 @@ void InitThingdef() qsort(&AFTable[0], AFTable.Size(), sizeof(AFTable[0]), funccmp); } - // Create a sorted list of native variables - if (variables.Size() == 0) - { - FAutoSegIterator probe(MRegHead, MRegTail); - - while (*++probe != NULL) - { - variables.Push((FVariableInfo *)*probe); - } - variables.ShrinkToFit(); - qsort(&variables[0], variables.Size(), sizeof(variables[0]), varcmp); - } + // Define some member variables we feel like exposing to the user + PSymbolTable &symt = RUNTIME_CLASS(AActor)->Symbols; + PType *array5 = NewArray(TypeSInt32, 5); + symt.AddSymbol(new PField(NAME_Alpha, TypeFixed, VARF_Native, myoffsetof(AActor,alpha))); + symt.AddSymbol(new PField(NAME_Angle, TypeAngle, VARF_Native, myoffsetof(AActor,angle))); + symt.AddSymbol(new PField(NAME_Args, array5, VARF_Native, myoffsetof(AActor,args))); + symt.AddSymbol(new PField(NAME_CeilingZ, TypeFixed, VARF_Native, myoffsetof(AActor,ceilingz))); + symt.AddSymbol(new PField(NAME_FloorZ, TypeFixed, VARF_Native, myoffsetof(AActor,floorz))); + symt.AddSymbol(new PField(NAME_Health, TypeSInt32, VARF_Native, myoffsetof(AActor,health))); + symt.AddSymbol(new PField(NAME_Mass, TypeSInt32, VARF_Native, myoffsetof(AActor,Mass))); + symt.AddSymbol(new PField(NAME_Pitch, TypeAngle, VARF_Native, myoffsetof(AActor,pitch))); + symt.AddSymbol(new PField(NAME_Roll, TypeAngle, VARF_Native, myoffsetof(AActor,roll))); + symt.AddSymbol(new PField(NAME_Special, TypeSInt32, VARF_Native, myoffsetof(AActor,special))); + symt.AddSymbol(new PField(NAME_TID, TypeSInt32, VARF_Native, myoffsetof(AActor,tid))); + symt.AddSymbol(new PField(NAME_TIDtoHate, TypeSInt32, VARF_Native, myoffsetof(AActor,TIDtoHate))); + symt.AddSymbol(new PField(NAME_WaterLevel, TypeSInt32, VARF_Native, myoffsetof(AActor,waterlevel))); + symt.AddSymbol(new PField(NAME_X, TypeFixed, VARF_Native, myoffsetof(AActor,x))); + symt.AddSymbol(new PField(NAME_Y, TypeFixed, VARF_Native, myoffsetof(AActor,y))); + symt.AddSymbol(new PField(NAME_Z, TypeFixed, VARF_Native, myoffsetof(AActor,z))); + symt.AddSymbol(new PField(NAME_VelX, TypeFixed, VARF_Native, myoffsetof(AActor,velx))); + symt.AddSymbol(new PField(NAME_VelY, TypeFixed, VARF_Native, myoffsetof(AActor,vely))); + symt.AddSymbol(new PField(NAME_VelZ, TypeFixed, VARF_Native, myoffsetof(AActor,velz))); + symt.AddSymbol(new PField(NAME_MomX, TypeFixed, VARF_Native, myoffsetof(AActor,velx))); + symt.AddSymbol(new PField(NAME_MomY, TypeFixed, VARF_Native, myoffsetof(AActor,vely))); + symt.AddSymbol(new PField(NAME_MomZ, TypeFixed, VARF_Native, myoffsetof(AActor,velz))); + symt.AddSymbol(new PField(NAME_ScaleX, TypeFixed, VARF_Native, myoffsetof(AActor,scaleX))); + symt.AddSymbol(new PField(NAME_ScaleY, TypeFixed, VARF_Native, myoffsetof(AActor,scaleY))); + symt.AddSymbol(new PField(NAME_Score, TypeSInt32, VARF_Native, myoffsetof(AActor,Score))); + symt.AddSymbol(new PField(NAME_Accuracy, TypeSInt32, VARF_Native, myoffsetof(AActor,accuracy))); + symt.AddSymbol(new PField(NAME_Stamina, TypeSInt32, VARF_Native, myoffsetof(AActor,stamina))); + symt.AddSymbol(new PField(NAME_Height, TypeFixed, VARF_Native, myoffsetof(AActor,height))); + symt.AddSymbol(new PField(NAME_Radius, TypeFixed, VARF_Native, myoffsetof(AActor,radius))); + symt.AddSymbol(new PField(NAME_ReactionTime,TypeSInt32, VARF_Native, myoffsetof(AActor,reactiontime))); + symt.AddSymbol(new PField(NAME_MeleeRange, TypeFixed, VARF_Native, myoffsetof(AActor,meleerange))); + symt.AddSymbol(new PField(NAME_Speed, TypeFixed, VARF_Native, myoffsetof(AActor,Speed))); } - diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 871ee35af..1061a1991 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -53,43 +53,6 @@ #include "m_fixed.h" #include "vmbuilder.h" -// Accessible actor member variables -DEFINE_MEMBER_VARIABLE(alpha, AActor) -DEFINE_MEMBER_VARIABLE(angle, AActor) -DEFINE_MEMBER_VARIABLE(args, AActor) -DEFINE_MEMBER_VARIABLE(ceilingz, AActor) -DEFINE_MEMBER_VARIABLE(floorz, AActor) -DEFINE_MEMBER_VARIABLE(health, AActor) -DEFINE_MEMBER_VARIABLE(Mass, AActor) -DEFINE_MEMBER_VARIABLE(pitch, AActor) -DEFINE_MEMBER_VARIABLE(special, AActor) -DEFINE_MEMBER_VARIABLE(special1, AActor) -DEFINE_MEMBER_VARIABLE(special2, AActor) -DEFINE_MEMBER_VARIABLE(tid, AActor) -DEFINE_MEMBER_VARIABLE(TIDtoHate, AActor) -DEFINE_MEMBER_VARIABLE(waterlevel, AActor) -DEFINE_MEMBER_VARIABLE(x, AActor) -DEFINE_MEMBER_VARIABLE(y, AActor) -DEFINE_MEMBER_VARIABLE(z, AActor) -DEFINE_MEMBER_VARIABLE(velx, AActor) -DEFINE_MEMBER_VARIABLE(vely, AActor) -DEFINE_MEMBER_VARIABLE(velz, AActor) -DEFINE_MEMBER_VARIABLE_ALIAS(momx, velx, AActor) -DEFINE_MEMBER_VARIABLE_ALIAS(momy, vely, AActor) -DEFINE_MEMBER_VARIABLE_ALIAS(momz, velz, AActor) -DEFINE_MEMBER_VARIABLE(scaleX, AActor) -DEFINE_MEMBER_VARIABLE(scaleY, AActor) -//DEFINE_MEMBER_VARIABLE(Damage, AActor) -DEFINE_MEMBER_VARIABLE(Score, AActor) -DEFINE_MEMBER_VARIABLE(accuracy, AActor) -DEFINE_MEMBER_VARIABLE(stamina, AActor) -DEFINE_MEMBER_VARIABLE(height, AActor) -DEFINE_MEMBER_VARIABLE(radius, AActor) -DEFINE_MEMBER_VARIABLE(reactiontime, AActor) -DEFINE_MEMBER_VARIABLE(meleerange, AActor) -DEFINE_MEMBER_VARIABLE(Speed, AActor) -DEFINE_MEMBER_VARIABLE(roll, AActor) - ExpEmit::ExpEmit(VMFunctionBuilder *build, int type) : RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false), Fixed(false) { @@ -3148,7 +3111,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) else { ReturnType = rets[0]; - // If more types are added to ParseNativeVariable(), add them here too. + // If more types are added to ParseNativeFunction(), add them here too. if (rets[0] == TypeSInt32) ValueType = VAL_Int; else if (rets[0] == TypeFloat64) ValueType = VAL_Float; else if (rets[0] == TypeAngle) ValueType = VAL_Angle; diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 0bb009f70..064d5a107 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -391,7 +391,7 @@ static void ParseArgListDef(FScanner &sc, PClassActor *cls, //========================================================================== void ParseFunctionDef(FScanner &sc, PClassActor *cls, FName funcname, - TArray<PType *> &rets, DWORD funcflags, unsigned int error) + TArray<PType *> &rets, DWORD funcflags) { assert(cls != NULL); @@ -403,7 +403,7 @@ void ParseFunctionDef(FScanner &sc, PClassActor *cls, FName funcname, if (afd == NULL) { sc.ScriptMessage ("The function '%s' has not been exported from the executable.", funcname.GetChars()); - ++error; + FScriptPosition::ErrorCounter++; } sc.MustGetToken('('); @@ -423,11 +423,7 @@ void ParseFunctionDef(FScanner &sc, PClassActor *cls, FName funcname, PFunction *sym = new PFunction(funcname); sym->AddVariant(NewPrototype(rets, args), argflags, *(afd->VMPointer)); sym->Flags = funcflags; - if (error) - { - FScriptPosition::ErrorCounter += error; - } - else if (cls->Symbols.AddSymbol(sym) == NULL) + if (cls->Symbols.AddSymbol(sym) == NULL) { delete sym; sc.ScriptMessage ("'%s' is already defined in class '%s'.", @@ -439,22 +435,20 @@ void ParseFunctionDef(FScanner &sc, PClassActor *cls, FName funcname, //========================================================================== // -// ParseNativeVariable +// ParseNativeFunction // -// Parses a native variable or non-action function declaration. +// Parses a non-action function declaration. // //========================================================================== -static void ParseNativeVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cls) +static void ParseNativeFunction(FScanner &sc, PClassActor *cls) { - PType *valuetype; - unsigned int error = 0; + TArray<PType *> rets(1); if (sc.LumpNum == -1 || Wads.GetLumpFile(sc.LumpNum) > 0) { - sc.ScriptMessage ("variables can only be imported by internal class and actor definitions!"); + sc.ScriptMessage ("functions can only be declared by native actors!"); FScriptPosition::ErrorCounter++; - error++; } // Read the type and make sure it's int or float. @@ -463,80 +457,33 @@ static void ParseNativeVariable (FScanner &sc, PSymbolTable *symt, PClassActor * { case TK_Int: case TK_Bool: - valuetype = TypeSInt32; + rets.Push(TypeSInt32); break; case TK_Float: - valuetype = TypeFloat64; + rets.Push(TypeFloat64); break; case TK_Angle_t: - valuetype = TypeAngle; + rets.Push(TypeAngle); break; case TK_Fixed_t: - valuetype = TypeFixed; + rets.Push(TypeFixed); break; case TK_Identifier: - valuetype = NULL; + rets.Push(NewPointer(RUNTIME_CLASS(DObject))); // Todo: Object type sc.ScriptError("Object type variables not implemented yet!"); break; default: - sc.ScriptError("Invalid variable type %s", sc.String); + sc.ScriptError("Invalid return type %s", sc.String); return; } - sc.MustGetToken(TK_Identifier); - FName symname = sc.String; - if (sc.CheckToken('(')) - { - TArray<PType *> rets; - - rets.Push(valuetype); - sc.UnGet(); - ParseFunctionDef(sc, cls, symname, rets, VARF_Method, error); - return; - } - else - { - if (sc.CheckToken('[')) - { - FxExpression *expr = ParseExpression (sc, cls); - if (!expr->isConstant()) - { - sc.ScriptError("Array size must be constant"); - } - int maxelems = static_cast<FxConstant *>(expr)->GetValue().GetInt(); - delete expr; - sc.MustGetToken(']'); - valuetype = NewArray(valuetype, maxelems); - } - sc.MustGetToken(';'); - - const FVariableInfo *vi = FindVariable(symname, cls); - if (vi == NULL) - { - sc.ScriptError("Unknown native variable '%s'", symname.GetChars()); - } - - PField *sym = new PField(symname, valuetype, VARF_Native); - sym->Offset = (unsigned)vi->address; // todo - - if (symt->AddSymbol(sym) == NULL) - { - delete sym; - sc.ScriptMessage ("'%s' is already defined in '%s'.", - symname.GetChars(), cls? cls->TypeName.GetChars() : "Global"); - FScriptPosition::ErrorCounter++; - } - else - { - cls->Fields.Push(sym); - } - } + ParseFunctionDef(sc, cls, sc.String, rets, VARF_Method); } //========================================================================== @@ -1089,7 +1036,7 @@ static void ParseActionDef (FScanner &sc, PClassActor *cls) if (sc.LumpNum == -1 || Wads.GetLumpFile(sc.LumpNum) > 0) { sc.ScriptMessage ("Action functions can only be imported by internal class and actor definitions!"); - ++error; + FScriptPosition::ErrorCounter++; } sc.MustGetToken(TK_Native); @@ -1100,7 +1047,7 @@ static void ParseActionDef (FScanner &sc, PClassActor *cls) } sc.MustGetToken(TK_Identifier); funcname = sc.String; - ParseFunctionDef(sc, cls, funcname, rets, VARF_Method | VARF_Action, error); + ParseFunctionDef(sc, cls, funcname, rets, VARF_Method | VARF_Action); } //========================================================================== @@ -1239,7 +1186,7 @@ static void ParseActor(FScanner &sc) break; case TK_Native: - ParseNativeVariable (sc, &info->Symbols, info); + ParseNativeFunction (sc, info); break; case TK_Var: @@ -1366,10 +1313,6 @@ void ParseDecorate (FScanner &sc) ParseEnum (sc, &GlobalSymbols, NULL); break; - case TK_Native: - ParseNativeVariable(sc, &GlobalSymbols, NULL); - break; - case ';': // ';' is the start of a comment in the non-cmode parser which // is used to parse parts of the DECORATE lump. If we don't add diff --git a/src/zzautozend.cpp b/src/zzautozend.cpp index ab61bc92c..54a506756 100644 --- a/src/zzautozend.cpp +++ b/src/zzautozend.cpp @@ -46,9 +46,6 @@ __declspec(allocate(".creg$z")) void *const CRegTail = 0; #pragma section(".greg$z",read) __declspec(allocate(".greg$z")) void *const GRegTail = 0; -#pragma section(".mreg$z",read) -__declspec(allocate(".mreg$z")) void *const MRegTail = 0; - #pragma section(".yreg$z",read) __declspec(allocate(".yreg$z")) void *const YRegTail = 0; @@ -60,7 +57,6 @@ __declspec(allocate(".yreg$z")) void *const YRegTail = 0; void *const ARegTail __attribute__((section(SECTION_AREG))) = 0; void *const CRegTail __attribute__((section(SECTION_CREG))) = 0; void *const GRegTail __attribute__((section(SECTION_GREG))) = 0; -void *const MRegTail __attribute__((section(SECTION_MREG))) = 0; void *const YRegTail __attribute__((section(SECTION_YREG))) = 0; #else diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index ebc14cdda..c68098d38 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -32,47 +32,12 @@ ACTOR Actor native //: Thinker RipLevelMin 0 RipLevelMax 0 - // Variables for the expression evaluator - // NOTE: fixed_t and angle_t are only used here to ensure proper conversion - // Internally they are handled as floats. - // Variables must be native. - native fixed_t alpha; - native angle_t angle; - native int args[5]; - native fixed_t ceilingz; - native fixed_t floorz; - native int health; - native int mass; - native angle_t pitch; - native int special; - native int tid; - native int TIDtoHate; - native int waterlevel; - //native int damage; - native fixed_t x; - native fixed_t y; - native fixed_t z; - native fixed_t velx; - native fixed_t vely; - native fixed_t velz; - native fixed_t momx; // alias for velx - native fixed_t momy; // alias for vely - native fixed_t momz; // alias for velz - native fixed_t scaleX; - native fixed_t scaleY; - native int score; - native int accuracy; - native int stamina; - native fixed_t height; - native fixed_t radius; - native int reactiontime; - native fixed_t meleerange; - native fixed_t speed; - native angle_t roll; - + // Functions native bool CheckClass(class<Actor> checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false); native bool IsPointerEqual(int ptr_select1, int ptr_select2); + // Action functions + // Meh, MBF redundant functions. Only for DeHackEd support. action native A_Turn(float angle = 0); action native A_LineEffect(int boomspecial = 0, int tag = 0); From 7898e189dffe2a46d834c07ea161e6327389869e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers <c.oelckers@zdoom.fake> Date: Tue, 28 Apr 2015 09:40:57 +0200 Subject: [PATCH 211/232] - fixed problems in CMake project files: * thingdef_function.cpp no longer exists * the build rule for zcc-parse.c was not correct. --- src/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 271ead5a1..31a2d2055 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -636,7 +636,7 @@ add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c ${CMAKE_CUR WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} DEPENDS lemon ${CMAKE_CURRENT_SOURCE_DIR}/xlat/xlat_parser.y ) -add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.lemon ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.h +add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.c ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.h COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/zscript/zcc-parse.lemon . COMMAND ${LEMON_EXE} zcc-parse.lemon WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} @@ -1081,7 +1081,6 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE thingdef/thingdef_data.cpp thingdef/thingdef_exp.cpp thingdef/thingdef_expression.cpp - thingdef/thingdef_function.cpp thingdef/thingdef_parse.cpp thingdef/thingdef_properties.cpp thingdef/thingdef_states.cpp From a13ada3b2d6460c418b3480a729a5857c533e482 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers <c.oelckers@zdoom.fake> Date: Tue, 28 Apr 2015 10:39:35 +0200 Subject: [PATCH 212/232] Revert "Merge commit '173dbd6bcee02a9e9c12a4a74d1fffe3e081d162' into scripting" This reverts commit e9cbb0b2235bdd95db01a52f2f8f01725e29f4cb, reversing changes made to d6e3fc0567ace7f5d5754d0f43f1ef09685121de. The merge just copied the obsolete FxFloatCast from master without any conflict so it all had to be removed again. --- src/thingdef/thingdef_exp.h | 19 ------- src/thingdef/thingdef_expression.cpp | 76 ---------------------------- 2 files changed, 95 deletions(-) diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index b81bac4f1..7277d48bb 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -389,25 +389,6 @@ public: }; -//========================================================================== -// -// -// -//========================================================================== - -class FxFloatCast : public FxExpression -{ - FxExpression *basex; - -public: - - FxFloatCast(FxExpression *x); - ~FxFloatCast(); - FxExpression *Resolve(FCompileContext&); - - ExpVal EvalExpression (AActor *self); -}; - //========================================================================== // // FxSign diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 92e34a038..e8e3c2b67 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -488,82 +488,6 @@ ExpEmit FxFloatCast::Emit(VMFunctionBuilder *build) return to; } -//========================================================================== -// -// -// -//========================================================================== - -FxFloatCast::FxFloatCast(FxExpression *x) -: FxExpression(x->ScriptPosition) -{ - basex = x; - ValueType = VAL_Float; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxFloatCast::~FxFloatCast() -{ - SAFE_DELETE(basex); -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxFloatCast::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE(basex, ctx); - - if (basex->ValueType == VAL_Float) - { - FxExpression *x = basex; - basex = NULL; - delete this; - return x; - } - else if (basex->ValueType == VAL_Int) - { - if (basex->isConstant()) - { - ExpVal constval = basex->EvalExpression(NULL); - FxExpression *x = new FxConstant(constval.GetFloat(), ScriptPosition); - delete this; - return x; - } - return this; - } - else - { - ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); - delete this; - return NULL; - } -} - -//========================================================================== -// -// -// -//========================================================================== - -ExpVal FxFloatCast::EvalExpression (AActor *self) -{ - ExpVal baseval = basex->EvalExpression(self); - baseval.Float = baseval.GetFloat(); - baseval.Type = VAL_Float; - return baseval; -} - - //========================================================================== // // From 2604905b0c55ba5b2fdc9f4fc11a5c643a734540 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers <c.oelckers@zdoom.fake> Date: Tue, 28 Apr 2015 12:03:06 +0200 Subject: [PATCH 213/232] - missed one compile error in last merge. --- src/c_cmds.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index 12c0027a3..39dbd2e5f 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -911,8 +911,8 @@ static void PrintFilteredActorList(const ActorTypeChecker IsActorType, const cha if (FilterName != NULL) { - FilterClass = PClass::FindClass(FilterName); - if (FilterClass == NULL || FilterClass->ActorInfo == NULL) + FilterClass = PClass::FindActor(FilterName); + if (FilterClass == NULL) { Printf("%s is not an actor class.\n", FilterName); return; From 137e624b55df76b07e28af8ce8ea251575a8f585 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers <c.oelckers@zdoom.fake> Date: Tue, 28 Apr 2015 15:12:21 +0200 Subject: [PATCH 214/232] - needed one more fix in CMake project. --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4e6b09a82..12218f997 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -670,7 +670,7 @@ add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c ${CMAKE_CUR add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.c ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.h COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/zscript/zcc-parse.lemon . - COMMAND ${LEMON_EXE} zcc-parse.lemon + COMMAND lemon zcc-parse.lemon WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} DEPENDS lemon ${CMAKE_CURRENT_SOURCE_DIR}/zscript/zcc-parse.lemon ) From 2d0f6339f7f7dde2d74dc9dee0085a500774b02d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers <c.oelckers@zdoom.fake> Date: Tue, 28 Apr 2015 15:34:48 +0200 Subject: [PATCH 215/232] - fixed some memory leaks: The global symbol table and the argument list for DECORATE called action specials were never freed. --- src/d_main.cpp | 2 ++ src/dobjtype.cpp | 10 ++++++++++ src/dobjtype.h | 2 ++ src/thingdef/thingdef_states.cpp | 2 +- src/win32/i_main.cpp | 2 +- src/win32/i_rawps2.cpp | 4 ++++ src/win32/i_xinput.cpp | 4 ++++ 7 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 6ea7e8ff5..2d10fa3dd 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2261,6 +2261,8 @@ void D_DoomMain (void) do { + InitGlobalSymbols(); + if (restart) { C_InitConsole(SCREENWIDTH, SCREENHEIGHT, false); diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index f7623f84d..d930256f6 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -517,8 +517,18 @@ void PType::StaticInit() TypeTable.AddType(TypeState = new PStatePointer); TypeTable.AddType(TypeFixed = new PFixed); TypeTable.AddType(TypeAngle = new PAngle); +} +void ReleaseGlobalSymbols() +{ + GlobalSymbols.ReleaseSymbols(); +} + +void InitGlobalSymbols() +{ // Add types to the global symbol table. + atterm(ReleaseGlobalSymbols); + GlobalSymbols.ReleaseSymbols(); GlobalSymbols.AddSymbol(new PSymbolType(NAME_sByte, TypeSInt8)); GlobalSymbols.AddSymbol(new PSymbolType(NAME_Byte, TypeUInt8)); GlobalSymbols.AddSymbol(new PSymbolType(NAME_Short, TypeSInt16)); diff --git a/src/dobjtype.h b/src/dobjtype.h index 92917f7ec..ff34a4b8f 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -801,4 +801,6 @@ public: PSymbolConstString() {} }; +void InitGlobalSymbols(); + #endif diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index fedfd924e..4696b7e57 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -72,11 +72,11 @@ FxVMFunctionCall *DoActionSpecials(FScanner &sc, FState & state, Baggage &bag) int min_args, max_args; FString specname = sc.String; - FArgumentList *args = new FArgumentList; int special = P_FindLineSpecial(sc.String, &min_args, &max_args); if (special > 0 && min_args >= 0) { + FArgumentList *args = new FArgumentList; args->Push(new FxParameter(new FxConstant(special, sc))); i = 0; diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp index 668c74f95..1404fc465 100644 --- a/src/win32/i_main.cpp +++ b/src/win32/i_main.cpp @@ -1279,7 +1279,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE nothing, LPSTR cmdline, int n _CrtSetDbgFlag (_CrtSetDbgFlag(0) | _CRTDBG_LEAK_CHECK_DF); // Use this to break at a specific allocation number. - //_crtBreakAlloc = 18800; + _crtBreakAlloc = 22884; #endif DoMain (hInstance); diff --git a/src/win32/i_rawps2.cpp b/src/win32/i_rawps2.cpp index 84fb605c6..0ca314504 100644 --- a/src/win32/i_rawps2.cpp +++ b/src/win32/i_rawps2.cpp @@ -1293,6 +1293,10 @@ void I_StartupRawPS2() { JoyDevices[INPUT_RawPS2] = joys; } + else + { + delete joys; + } } } } diff --git a/src/win32/i_xinput.cpp b/src/win32/i_xinput.cpp index 5a02d7af4..cc1dce6ee 100644 --- a/src/win32/i_xinput.cpp +++ b/src/win32/i_xinput.cpp @@ -783,6 +783,10 @@ void I_StartupXInput() { JoyDevices[INPUT_XInput] = joys; } + else + { + delete joys; + } } } } From 450e5aec52e8885dec0b6b89ae630826ec8e27db Mon Sep 17 00:00:00 2001 From: Christoph Oelckers <c.oelckers@zdoom.fake> Date: Tue, 28 Apr 2015 15:45:10 +0200 Subject: [PATCH 216/232] - this shouldn't have been committed. --- src/win32/i_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp index 1404fc465..846843cc6 100644 --- a/src/win32/i_main.cpp +++ b/src/win32/i_main.cpp @@ -1279,7 +1279,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE nothing, LPSTR cmdline, int n _CrtSetDbgFlag (_CrtSetDbgFlag(0) | _CRTDBG_LEAK_CHECK_DF); // Use this to break at a specific allocation number. - _crtBreakAlloc = 22884; + //_crtBreakAlloc = 53039; #endif DoMain (hInstance); From 91b05366d667cbbaa4e082da972e9e7e1715298e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers <c.oelckers@zdoom.fake> Date: Tue, 28 Apr 2015 16:39:20 +0200 Subject: [PATCH 217/232] - tried to make 'restart' CCMD work again. This requires quite a bit more thorough cleanup. I got it to the point where the titlepic appears after restarting, but it still crashes when starting the game so there's more data that needs to be cleaned up... --- src/d_main.cpp | 7 ++++--- src/dobjtype.cpp | 31 ++++++++++++++++++++----------- src/dobjtype.h | 2 +- src/fragglescript/t_script.cpp | 1 + 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 2d10fa3dd..c68af4121 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1973,8 +1973,6 @@ static void D_DoomInit() M_FindResponseFile (); atterm(FinalGC); - PClass::StaticInit(); - PType::StaticInit(); // Combine different file parameters with their pre-switch bits. Args->CollectFiles("-deh", ".deh"); @@ -2261,7 +2259,8 @@ void D_DoomMain (void) do { - InitGlobalSymbols(); + PClass::StaticInit(); + PType::StaticInit(); if (restart) { @@ -2637,6 +2636,8 @@ void D_DoomMain (void) S_Shutdown(); // free all channels and delete playlist C_ClearAliases(); // CCMDs won't be reinitialized so these need to be deleted here DestroyCVarsFlagged(CVAR_MOD); // Delete any cvar left by mods + ReleaseGlobalSymbols(); + PClass::StaticShutdown(); GC::FullGC(); // perform one final garbage collection before deleting the class data restart++; diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index d930256f6..1786eab77 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -472,8 +472,17 @@ void PType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const // //========================================================================== +void ReleaseGlobalSymbols() +{ + TypeTable.Clear(); + GlobalSymbols.ReleaseSymbols(); +} + void PType::StaticInit() { + // Add types to the global symbol table. + atterm(ReleaseGlobalSymbols); + // Set up TypeTable hash keys. RUNTIME_CLASS(PErrorType)->TypeTableType = RUNTIME_CLASS(PErrorType); RUNTIME_CLASS(PVoidType)->TypeTableType = RUNTIME_CLASS(PVoidType); @@ -517,18 +526,7 @@ void PType::StaticInit() TypeTable.AddType(TypeState = new PStatePointer); TypeTable.AddType(TypeFixed = new PFixed); TypeTable.AddType(TypeAngle = new PAngle); -} -void ReleaseGlobalSymbols() -{ - GlobalSymbols.ReleaseSymbols(); -} - -void InitGlobalSymbols() -{ - // Add types to the global symbol table. - atterm(ReleaseGlobalSymbols); - GlobalSymbols.ReleaseSymbols(); GlobalSymbols.AddSymbol(new PSymbolType(NAME_sByte, TypeSInt8)); GlobalSymbols.AddSymbol(new PSymbolType(NAME_Byte, TypeUInt8)); GlobalSymbols.AddSymbol(new PSymbolType(NAME_Short, TypeSInt16)); @@ -2061,6 +2059,17 @@ void PClass::StaticShutdown () } TypeTable.Clear(); bShutdown = true; + + AllClasses.Clear(); + PClassActor::AllActorClasses.Clear(); + + FAutoSegIterator probe(CRegHead, CRegTail); + + while (*++probe != NULL) + { + ((ClassReg *)*probe)->MyClass = NULL; + } + } //========================================================================== diff --git a/src/dobjtype.h b/src/dobjtype.h index ff34a4b8f..313130ddb 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -801,6 +801,6 @@ public: PSymbolConstString() {} }; -void InitGlobalSymbols(); +void ReleaseGlobalSymbols(); #endif diff --git a/src/fragglescript/t_script.cpp b/src/fragglescript/t_script.cpp index 98911a418..5f62fe6ac 100644 --- a/src/fragglescript/t_script.cpp +++ b/src/fragglescript/t_script.cpp @@ -170,6 +170,7 @@ DFsScript::DFsScript() void DFsScript::Destroy() { + if (this == global_script) global_script = NULL; ClearVariables(true); ClearSections(); ClearChildren(); From afa022605a3698e099c7a7db2376f8a46fd26349 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers <c.oelckers@zdoom.fake> Date: Tue, 28 Apr 2015 19:03:52 +0200 Subject: [PATCH 218/232] - some more fixes of 'Restart'. Still not working as intended. --- src/dobjtype.cpp | 2 ++ src/fragglescript/t_fs.h | 1 + src/fragglescript/t_script.cpp | 37 +++++++++++++++------------- src/thingdef/thingdef.cpp | 1 + src/thingdef/thingdef_data.cpp | 1 + src/thingdef/thingdef_properties.cpp | 2 ++ 6 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 1786eab77..18a3b47f0 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -45,6 +45,7 @@ #include "v_text.h" #include "a_pickups.h" #include "d_player.h" +#include "fragglescript/t_fs.h" // MACROS ------------------------------------------------------------------ @@ -2032,6 +2033,7 @@ void PClass::StaticShutdown () TArray<size_t *> uniqueFPs(64); unsigned int i, j; + FS_Close(); // this must be done before the classes get deleted. for (i = 0; i < PClass::AllClasses.Size(); ++i) { PClass *type = PClass::AllClasses[i]; diff --git a/src/fragglescript/t_fs.h b/src/fragglescript/t_fs.h index 91f90edb3..78a6f9337 100644 --- a/src/fragglescript/t_fs.h +++ b/src/fragglescript/t_fs.h @@ -10,5 +10,6 @@ class AActor; void T_PreprocessScripts(); void T_LoadScripts(MapData * map); void T_AddSpawnedThing(AActor * ); +void FS_Close(); #endif diff --git a/src/fragglescript/t_script.cpp b/src/fragglescript/t_script.cpp index 5f62fe6ac..48f0c6250 100644 --- a/src/fragglescript/t_script.cpp +++ b/src/fragglescript/t_script.cpp @@ -670,24 +670,28 @@ void FS_Close() int i; DFsVariable *current, *next; - // we have to actually delete the global variables if we don't want - // to get them reported as memory leaks. - for(i=0; i<VARIABLESLOTS; i++) - { - current = global_script->variables[i]; - - while(current) + if (global_script != NULL) + { + // we have to actually delete the global variables if we don't want + // to get them reported as memory leaks. + for (i = 0; i < VARIABLESLOTS; i++) { - next = current->next; // save for after freeing - - current->ObjectFlags |= OF_YesReallyDelete; - delete current; - current = next; // go to next in chain + current = global_script->variables[i]; + + while (current) + { + next = current->next; // save for after freeing + + current->ObjectFlags |= OF_YesReallyDelete; + delete current; + current = next; // go to next in chain + } } - } - GC::DelSoftRoot(global_script); - global_script->ObjectFlags |= OF_YesReallyDelete; - delete global_script; + GC::DelSoftRoot(global_script); + global_script->ObjectFlags |= OF_YesReallyDelete; + delete global_script; + global_script = NULL; + } } void T_Init() @@ -701,7 +705,6 @@ void T_Init() global_script = new DFsScript; GC::AddSoftRoot(global_script); init_functions(); - atterm(FS_Close); } } diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 60a0da8de..c0097a053 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -218,6 +218,7 @@ void FinishActor(const FScriptPosition &sc, PClassActor *info, Baggage &bag) if (bag.DropItemSet) { info->DropItems = bag.DropItemList; + GC::WriteBarrier(info, info->DropItems); } if (info->IsDescendantOf (RUNTIME_CLASS(AInventory))) { diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index d161fef6d..ca4c9b487 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -594,6 +594,7 @@ void InitThingdef() } // Create a sorted list of native action functions + AFTable.Clear(); if (AFTable.Size() == 0) { FAutoSegIterator probe(ARegHead, ARegTail); diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index 61098797f..17d080090 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -797,6 +797,7 @@ DEFINE_PROPERTY(dropitem, S_i_i, Actor) } di->Next = bag.DropItemList; bag.DropItemList = di; + GC::WriteBarrier(di); } //========================================================================== @@ -2739,6 +2740,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn) } di->Next = bag.DropItemList; bag.DropItemList = di; + GC::WriteBarrier(di); } //========================================================================== From 0f8972c96b1b5ae56415613f28f02b3f38290a1c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers <c.oelckers@zdoom.fake> Date: Tue, 28 Apr 2015 21:30:12 +0200 Subject: [PATCH 219/232] - don't delete any DObjects FraggleScript's global_script was deleted instead of destroyed. --- src/fragglescript/t_script.cpp | 22 +--------------------- src/p_enemy.cpp | 12 ++++++------ 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/src/fragglescript/t_script.cpp b/src/fragglescript/t_script.cpp index 48f0c6250..72e1e4ae8 100644 --- a/src/fragglescript/t_script.cpp +++ b/src/fragglescript/t_script.cpp @@ -170,7 +170,6 @@ DFsScript::DFsScript() void DFsScript::Destroy() { - if (this == global_script) global_script = NULL; ClearVariables(true); ClearSections(); ClearChildren(); @@ -667,29 +666,10 @@ static int LS_FS_Execute (line_t *ln, AActor *it, bool backSide, void FS_Close() { - int i; - DFsVariable *current, *next; - if (global_script != NULL) { - // we have to actually delete the global variables if we don't want - // to get them reported as memory leaks. - for (i = 0; i < VARIABLESLOTS; i++) - { - current = global_script->variables[i]; - - while (current) - { - next = current->next; // save for after freeing - - current->ObjectFlags |= OF_YesReallyDelete; - delete current; - current = next; // go to next in chain - } - } GC::DelSoftRoot(global_script); - global_script->ObjectFlags |= OF_YesReallyDelete; - delete global_script; + global_script->Destroy(); global_script = NULL; } } diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 7e0332963..25b3c8767 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -2892,8 +2892,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceTarget) PARAM_ANGLE_OPT(max_turn) { max_turn = 0; } PARAM_ANGLE_OPT(max_pitch) { max_pitch = 270; } PARAM_ANGLE_OPT(ang_offset) { max_turn = 0; } - PARAM_ANGLE_OPT(pitch_offset) { max_turn = 0; } - PARAM_INT_OPT(flags) { max_turn = 0; } + PARAM_ANGLE_OPT(pitch_offset) { pitch_offset = 0; } + PARAM_INT_OPT(flags) { flags = 0; } A_FaceTarget(self, max_turn, max_pitch, ang_offset, pitch_offset, flags); return 0; @@ -2905,8 +2905,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceMaster) PARAM_ANGLE_OPT(max_turn) { max_turn = 0; } PARAM_ANGLE_OPT(max_pitch) { max_pitch = 270; } PARAM_ANGLE_OPT(ang_offset) { max_turn = 0; } - PARAM_ANGLE_OPT(pitch_offset) { max_turn = 0; } - PARAM_INT_OPT(flags) { max_turn = 0; } + PARAM_ANGLE_OPT(pitch_offset) { pitch_offset = 0; } + PARAM_INT_OPT(flags) { flags = 0; } A_FaceMaster(self, max_turn, max_pitch, ang_offset, pitch_offset, flags); return 0; @@ -2918,8 +2918,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceTracer) PARAM_ANGLE_OPT(max_turn) { max_turn = 0; } PARAM_ANGLE_OPT(max_pitch) { max_pitch = 270; } PARAM_ANGLE_OPT(ang_offset) { max_turn = 0; } - PARAM_ANGLE_OPT(pitch_offset) { max_turn = 0; } - PARAM_INT_OPT(flags) { max_turn = 0; } + PARAM_ANGLE_OPT(pitch_offset) { pitch_offset = 0; } + PARAM_INT_OPT(flags) { flags = 0; } A_FaceTracer(self, max_turn, max_pitch, ang_offset, pitch_offset, flags); return 0; From 407d38f3d6df2cbbf399ce305033766d099cf94a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers <c.oelckers@zdoom.fake> Date: Tue, 28 Apr 2015 21:54:30 +0200 Subject: [PATCH 220/232] - add a bit more stuff that needs to be done before a restart to ensure that all obsolete data is taken down. (There's still a problem with the garbage collector kicking in and deleting stuff it's not supposed to, so Restart still doesn't work) --- src/d_main.cpp | 19 +++++++++++++++++++ src/dobject.h | 4 ++++ 2 files changed, 23 insertions(+) diff --git a/src/d_main.cpp b/src/d_main.cpp index c68af4121..2107763e7 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -107,6 +107,8 @@ #include "resourcefiles/resourcefile.h" #include "r_renderer.h" #include "p_local.h" +#include "autosegs.h" +#include "fragglescript/t_fs.h" EXTERN_CVAR(Bool, hud_althud) void DrawHUD(); @@ -2636,10 +2638,27 @@ void D_DoomMain (void) S_Shutdown(); // free all channels and delete playlist C_ClearAliases(); // CCMDs won't be reinitialized so these need to be deleted here DestroyCVarsFlagged(CVAR_MOD); // Delete any cvar left by mods + + GC::FullGC(); // clean up before taking down the object list. + + // Delete the VM functions here. The garbage collector will not do this automatically because they are referenced from the global action function definitions. + FAutoSegIterator probe(ARegHead, ARegTail); + while (*++probe != NULL) + { + AFuncDesc *afunc = (AFuncDesc *)*probe; + *(afunc->VMPointer) = NULL; + } + ReleaseGlobalSymbols(); PClass::StaticShutdown(); GC::FullGC(); // perform one final garbage collection before deleting the class data + + for (DObject *obj = GC::Root; obj; obj = obj->ObjNext) + { + obj->ClearClass(); // Delete the Class pointer because the data it points to has been deleted. This will automatically be reset if needed. + } + restart++; } } diff --git a/src/dobject.h b/src/dobject.h index 40445c8a0..4b6f1ec49 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -462,6 +462,10 @@ public: void SerializeUserVars(FArchive &arc); virtual void Serialize (FArchive &arc); + void ClearClass() + { + Class = NULL; + } // For catching Serialize functions in derived classes // that don't call their base class. From e42b688afa1937707c8620e652b67371c709c194 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers <c.oelckers@zdoom.fake> Date: Tue, 28 Apr 2015 23:37:04 +0200 Subject: [PATCH 221/232] - finally found the reason why the garbage collector went haywire after a restart: PClass::StaticShutdown set the PClass::bShutdown variable which disables much of the garbage collector. This needs to be cleared after successful cleanup. Restart works now, except for some random CCMDs being executed right afterward. - fixed incorrect variable init in A_Face* functions which was missed before. --- src/d_main.cpp | 3 ++- src/p_enemy.cpp | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 2107763e7..dad3e5712 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2652,7 +2652,7 @@ void D_DoomMain (void) ReleaseGlobalSymbols(); PClass::StaticShutdown(); - GC::FullGC(); // perform one final garbage collection before deleting the class data + GC::FullGC(); // perform one final garbage collection after shutdown for (DObject *obj = GC::Root; obj; obj = obj->ObjNext) { @@ -2660,6 +2660,7 @@ void D_DoomMain (void) } restart++; + PClass::bShutdown = false; } } while (1); diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 25b3c8767..640fef3fa 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -2891,7 +2891,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceTarget) PARAM_ACTION_PROLOGUE; PARAM_ANGLE_OPT(max_turn) { max_turn = 0; } PARAM_ANGLE_OPT(max_pitch) { max_pitch = 270; } - PARAM_ANGLE_OPT(ang_offset) { max_turn = 0; } + PARAM_ANGLE_OPT(ang_offset) { ang_offset = 0; } PARAM_ANGLE_OPT(pitch_offset) { pitch_offset = 0; } PARAM_INT_OPT(flags) { flags = 0; } @@ -2904,7 +2904,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceMaster) PARAM_ACTION_PROLOGUE; PARAM_ANGLE_OPT(max_turn) { max_turn = 0; } PARAM_ANGLE_OPT(max_pitch) { max_pitch = 270; } - PARAM_ANGLE_OPT(ang_offset) { max_turn = 0; } + PARAM_ANGLE_OPT(ang_offset) { ang_offset = 0; } PARAM_ANGLE_OPT(pitch_offset) { pitch_offset = 0; } PARAM_INT_OPT(flags) { flags = 0; } @@ -2917,7 +2917,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceTracer) PARAM_ACTION_PROLOGUE; PARAM_ANGLE_OPT(max_turn) { max_turn = 0; } PARAM_ANGLE_OPT(max_pitch) { max_pitch = 270; } - PARAM_ANGLE_OPT(ang_offset) { max_turn = 0; } + PARAM_ANGLE_OPT(ang_offset) { ang_offset = 0; } PARAM_ANGLE_OPT(pitch_offset) { pitch_offset = 0; } PARAM_INT_OPT(flags) { flags = 0; } From 4c17bd65a45c49675a5347e8f68b453090477756 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers <c.oelckers@zdoom.fake> Date: Wed, 29 Apr 2015 01:03:50 +0200 Subject: [PATCH 222/232] - parameters for FRandomPick should not be added up. (I hope that this code is correct, all I can judge it by is the assert not being triggered.) --- src/thingdef/thingdef_expression.cpp | 1 + src/zscript/vmbuilder.h | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 9625d83ee..1ab720c35 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -2189,6 +2189,7 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build) { double val = static_cast<FxConstant *>(choices[i])->GetValue().GetFloat(); build->Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, build->GetConstantFloat(val)); + build->ParamChange(-1); // all params should use the same register here. } } else diff --git a/src/zscript/vmbuilder.h b/src/zscript/vmbuilder.h index b8b1df848..ee15e49cf 100644 --- a/src/zscript/vmbuilder.h +++ b/src/zscript/vmbuilder.h @@ -51,6 +51,9 @@ public: void FillAddressConstants(FVoidObj *konst, VM_ATAG *tags); void FillStringConstants(FString *strings); + // PARAM increases ActiveParam; CALL decreases it. + void ParamChange(int delta); + // Track available registers. RegAvailability Registers[4]; @@ -76,8 +79,6 @@ private: TArray<VMOP> Code; - // PARAM increases ActiveParam; CALL decreases it. - void ParamChange(int delta); }; #endif From 7b6b473ec4f218a92868eeb8275c093dc5e2693e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers <c.oelckers@zdoom.fake> Date: Wed, 29 Apr 2015 11:28:04 +0200 Subject: [PATCH 223/232] - some GCC fixed by Edward-san. --- src/autosegs.h | 3 ++- src/d_dehacked.cpp | 2 +- src/d_netinfo.cpp | 2 +- src/dobjtype.cpp | 4 ++-- src/tarray.h | 23 +++++++++++++++++++---- src/thingdef/thingdef_codeptr.cpp | 4 ++-- src/thingdef/thingdef_expression.cpp | 2 +- src/zscript/ast.cpp | 2 +- src/zscript/vm.h | 4 ++-- src/zscript/zcc_expr.cpp | 2 ++ 10 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/autosegs.h b/src/autosegs.h index b32594d84..61872610c 100644 --- a/src/autosegs.h +++ b/src/autosegs.h @@ -37,6 +37,7 @@ #define REGMARKER(x) (x) typedef void * const REGINFO; +typedef void * NCREGINFO; // List of Action functons extern REGINFO ARegHead; @@ -72,7 +73,7 @@ class FAutoSegIterator } Probe = Head; } - REGINFO operator*() const + NCREGINFO operator*() const { return *Probe; } diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 9d7bcd6b5..1f346d526 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -792,7 +792,7 @@ void SetDehParams(FState *state, int codepointer) sym = dyn_cast<PFunction>(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(FName(MBFCodePointers[codepointer].name), true)); if (sym == NULL) return; - if (codepointer < 0 || codepointer >= countof(MBFCodePointerFactories)) + if (codepointer < 0 || (unsigned)codepointer >= countof(MBFCodePointerFactories)) { // This simply should not happen. Printf("Unmanaged dehacked codepointer alias num %i\n", codepointer); diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index 8bec1bcca..5814c0327 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -723,7 +723,7 @@ void D_WriteUserInfoStrings (int pnum, BYTE **stream, bool compact) case NAME_PlayerClass: *stream += sprintf(*((char **)stream), "\\%s", info->GetPlayerClassNum() == -1 ? "Random" : - D_EscapeUserInfo(info->GetPlayerClassType()->DisplayName.GetChars())); + D_EscapeUserInfo(info->GetPlayerClassType()->DisplayName.GetChars()).GetChars()); break; case NAME_Skin: diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 18a3b47f0..cc0a077f2 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -101,7 +101,7 @@ void DumpTypeTable() for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i) { int len = 0; - Printf("%4d:", i); + Printf("%4zu:", i); for (PType *ty = TypeTable.TypeHash[i]; ty != NULL; ty = ty->HashNext) { Printf(" -> %s", ty->IsKindOf(RUNTIME_CLASS(PNamedType)) ? static_cast<PNamedType*>(ty)->TypeName.GetChars(): ty->GetClass()->TypeName.GetChars()); @@ -122,7 +122,7 @@ void DumpTypeTable() } Printf("\n"); } - Printf("Used buckets: %d/%u (%.2f%%) for %d entries\n", used, countof(TypeTable.TypeHash), double(used)/countof(TypeTable.TypeHash)*100, all); + Printf("Used buckets: %d/%lu (%.2f%%) for %d entries\n", used, countof(TypeTable.TypeHash), double(used)/countof(TypeTable.TypeHash)*100, all); Printf("Min bucket size: %d\n", min); Printf("Max bucket size: %d\n", max); Printf("Avg bucket size: %.2f\n", double(all) / used); diff --git a/src/tarray.h b/src/tarray.h index 84a21728c..d62d75e28 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -389,7 +389,7 @@ public: if ((*this)[i] != NULL) delete (*this)[i]; } - Clear(); + this->Clear(); } }; @@ -461,7 +461,12 @@ template<class KT> struct THashTraits { // Returns the hash value for a key. hash_t Hash(const KT key) { return (hash_t)(intptr_t)key; } - hash_t Hash(double key) { return ((hash_t *)&key)[0] ^ ((hash_t *)&key)[1]; } + hash_t Hash(double key) + { + hash_t keyhash[2]; + memcpy(&keyhash, &key, sizeof(keyhash)); + return keyhash[0] ^ keyhash[1]; + } // Compares two keys, returning zero if they are the same. int Compare(const KT left, const KT right) { return left != right; } @@ -470,14 +475,24 @@ template<class KT> struct THashTraits template<> struct THashTraits<float> { // Use all bits when hashing singles instead of converting them to ints. - hash_t Hash(float key) { return *((hash_t *)&key); } + hash_t Hash(float key) + { + hash_t keyhash; + memcpy(&keyhash, &key, sizeof(keyhash)); + return keyhash; + } int Compare(float left, float right) { return left != right; } }; template<> struct THashTraits<double> { // Use all bits when hashing doubles instead of converting them to ints. - hash_t Hash(double key) { return ((hash_t *)&key)[0] ^ ((hash_t *)&key)[1]; } + hash_t Hash(double key) + { + hash_t keyhash[2]; + memcpy(&keyhash, &key, sizeof(keyhash)); + return keyhash[0] ^ keyhash[1]; + } int Compare(double left, double right) { return left != right; } }; diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index aaaf2d4f4..302d22f68 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -4350,8 +4350,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRoll) { PARAM_ACTION_PROLOGUE; PARAM_ANGLE (roll); - PARAM_INT_OPT (flags); { flags = 0; } - PARAM_INT_OPT (ptr); { ptr = AAPTR_DEFAULT; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_INT_OPT (ptr) { ptr = AAPTR_DEFAULT; } AActor *ref = COPY_AAPTR(self, ptr); if (ref != NULL) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 1ab720c35..a877a4e1a 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3130,7 +3130,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) return NULL; } TArray<PType *> &rets = Function->Variants[0].Proto->ReturnTypes; - if (rets.Size() == NULL) + if (rets.Size() == 0) { ReturnType = TypeVoid; } diff --git a/src/zscript/ast.cpp b/src/zscript/ast.cpp index c7ebf801e..bc1966142 100644 --- a/src/zscript/ast.cpp +++ b/src/zscript/ast.cpp @@ -83,7 +83,7 @@ public: NeedSpace = false; if (NestDepth > 0) { - Str.AppendFormat("%*s", NestDepth, ""); + Str.AppendFormat("%*s", (int)NestDepth, ""); } if (ConsecOpens > 0) { diff --git a/src/zscript/vm.h b/src/zscript/vm.h index 06f289bb4..1bbded861 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -476,8 +476,8 @@ struct VMValue { Kill(); a = v; - atag = atag; - Type = atag; + this->atag = atag; + Type = REGT_POINTER; } void SetNil() { diff --git a/src/zscript/zcc_expr.cpp b/src/zscript/zcc_expr.cpp index 32d0c9374..3ab977a2f 100644 --- a/src/zscript/zcc_expr.cpp +++ b/src/zscript/zcc_expr.cpp @@ -663,7 +663,9 @@ static void DtoS(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) // Convert to a string with enough precision such that converting // back to a double will not lose any data. char str[64]; + IGNORE_FORMAT_PRE int len = mysnprintf(str, countof(str), "%H", expr->DoubleVal); + IGNORE_FORMAT_POST expr->StringVal = str_arena.Alloc(str, len); expr->Type = TypeString; } From 99fc685a0170de6d023089c41269eda7c33e57e7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers <c.oelckers@zdoom.fake> Date: Sat, 2 May 2015 22:57:29 +0200 Subject: [PATCH 224/232] - allow linefeed before braces starting a compound state action definition. --- src/thingdef/thingdef_states.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index 4696b7e57..a44fa1ed1 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -253,7 +253,7 @@ do_stop: state.TicRange = 0; } - while (sc.GetString() && !sc.Crossed) + while (sc.GetString() && (!sc.Crossed || sc.Compare("{"))) { if (sc.Compare("BRIGHT")) { From 6996a15235a1eb2f167ca0bc2657731c58276004 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers <c.oelckers@zdoom.fake> Date: Sat, 2 May 2015 23:44:54 +0200 Subject: [PATCH 225/232] - fixed some overlooked merging problem. --- src/thingdef/thingdef_codeptr.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index ce929b9ce..be9c06d60 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -4597,11 +4597,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) ACTION_SET_RESULT(false); if (!ref) { - ACTION_SET_RESULT(false); return numret; } - if ((ref->flags2 & MF2_NOTELEPORT) && !(Flags & TF_OVERRIDE)) + if ((ref->flags2 & MF2_NOTELEPORT) && !(flags & TF_OVERRIDE)) { return numret; } From 96fa3b124ee54cd0bb99fb958984a797012f985a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers <c.oelckers@zdoom.fake> Date: Wed, 6 May 2015 23:24:27 +0200 Subject: [PATCH 226/232] - fixed: Trying to remove sector tags for line-less sectors crashed when there were no sector tags at all in a map. --- src/p_tags.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/p_tags.cpp b/src/p_tags.cpp index 851c4ee94..c08caec8f 100644 --- a/src/p_tags.cpp +++ b/src/p_tags.cpp @@ -98,13 +98,16 @@ void FTagManager::AddSectorTag(int sector, int tag) void FTagManager::RemoveSectorTags(int sect) { - int start = startForSector[sect]; - if (start >= 0) + if (startForSector.Size() > 0) { - while (allTags[start].target == sect) + int start = startForSector[sect]; + if (start >= 0) { - allTags[start].tag = allTags[start].target = -1; - start++; + while (allTags[start].target == sect) + { + allTags[start].tag = allTags[start].target = -1; + start++; + } } } } From 245a46735d52ca0dca332757045ca3ca7ace77ea Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@users.noreply.github.com> Date: Sat, 13 Jun 2015 18:19:09 -0500 Subject: [PATCH 227/232] Fix warning in assert statement --- src/name.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/name.cpp b/src/name.cpp index 07482ec52..5ab361d42 100644 --- a/src/name.cpp +++ b/src/name.cpp @@ -182,7 +182,7 @@ void FName::NameManager::InitBuckets () // Register built-in names. 'None' must be name 0. for (size_t i = 0; i < countof(PredefinedNames); ++i) { - assert(NULL == FindName(PredefinedNames[i], true) && "Predefined name already inserted"); + assert((NULL == FindName(PredefinedNames[i], true)) && "Predefined name already inserted"); FindName (PredefinedNames[i], false); } } From 1482070207dcba155410d72fbe3294a0e93a5bc8 Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@users.noreply.github.com> Date: Sat, 13 Jun 2015 18:19:38 -0500 Subject: [PATCH 228/232] Comment out SCOPE parsing for now --- src/zscript/zcc-parse.lemon | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index d94eb582c..6f3de56cb 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -850,12 +850,13 @@ primary(X) ::= primary(A) SUBSUB. /* postfix-- */ UNARY_EXPR(A,PEX_PostDec); X = expr1; } +/* primary(X) ::= SCOPE primary(B). { BINARY_EXPR(NULL,B,PEX_Scope); X = expr2; } - +*/ /*----- Unary Expressions -----*/ unary_expr(X) ::= primary(A). From 40a2665726e8a7754ef70cf1039295fd781c5984 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers <c.oelckers@zdoom.fake> Date: Sat, 1 Aug 2015 11:56:44 +0200 Subject: [PATCH 229/232] - fixed incorrect Strife player death sound. --- wadsrc/static/filter/game-strife/sndinfo.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/filter/game-strife/sndinfo.txt b/wadsrc/static/filter/game-strife/sndinfo.txt index 22f9b8356..f602a969b 100644 --- a/wadsrc/static/filter/game-strife/sndinfo.txt +++ b/wadsrc/static/filter/game-strife/sndinfo.txt @@ -8,7 +8,7 @@ $rolloff * 200 1200 $playersound player male *death dspldeth -$playersound player male *xdeath dspdiehi +$playersound player male *xdeath dsplxdth $playersound player male *gibbed dsslop $playersound player male *pain100 dsplpain $playersounddup player male *pain75 *pain100 From 1faf68794bcc7bedeaa81cf3958fb6ef23453fba Mon Sep 17 00:00:00 2001 From: Christoph Oelckers <c.oelckers@zdoom.fake> Date: Tue, 19 Jan 2016 13:59:53 +0100 Subject: [PATCH 230/232] - fixed the merge. --- src/g_heretic/a_knight.cpp | 3 ++- src/g_raven/a_minotaur.cpp | 1 - src/g_shared/a_debris.cpp | 2 -- src/g_strife/a_inquisitor.cpp | 2 ++ src/g_strife/a_programmer.cpp | 2 ++ src/g_strife/a_spectral.cpp | 1 - src/g_strife/a_strifestuff.cpp | 2 ++ src/g_strife/a_thingstoblowup.cpp | 3 --- src/p_local.h | 3 ++- 9 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/g_heretic/a_knight.cpp b/src/g_heretic/a_knight.cpp index d4bb583d9..d4cbb83d1 100644 --- a/src/g_heretic/a_knight.cpp +++ b/src/g_heretic/a_knight.cpp @@ -62,9 +62,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_KnightAttack) if (self->flags & MF_SHADOW || pr_knightatk () < 40) { // Red axe P_SpawnMissileZ (self, self->Z() + 36*FRACUNIT, self->target, PClass::FindActor("RedAxe")); - return; + return 0; } // Green axe P_SpawnMissileZ (self, self->Z() + 36*FRACUNIT, self->target, PClass::FindActor("KnightAxe")); + return 0; } diff --git a/src/g_raven/a_minotaur.cpp b/src/g_raven/a_minotaur.cpp index 2c15abece..14757c43b 100644 --- a/src/g_raven/a_minotaur.cpp +++ b/src/g_raven/a_minotaur.cpp @@ -389,7 +389,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_MntrFloorFire) PARAM_ACTION_PROLOGUE; AActor *mo; - fixed_t x, y; self->SetZ(self->floorz); fixedvec2 pos = self->Vec2Offset( diff --git a/src/g_shared/a_debris.cpp b/src/g_shared/a_debris.cpp index 6ab3a6450..edce7c1b2 100644 --- a/src/g_shared/a_debris.cpp +++ b/src/g_shared/a_debris.cpp @@ -31,10 +31,8 @@ IMPLEMENT_CLASS(AGlassShard) void P_SpawnDirt (AActor *actor, fixed_t radius) { - fixed_t x,y,z; PClassActor *dtype = NULL; AActor *mo; - angle_t angle; fixedvec3 pos = actor->Vec3Angle(radius, pr_dirt() << 24, (pr_dirt() << 9) + FRACUNIT); diff --git a/src/g_strife/a_inquisitor.cpp b/src/g_strife/a_inquisitor.cpp index 7cf9af1eb..ae5269929 100644 --- a/src/g_strife/a_inquisitor.cpp +++ b/src/g_strife/a_inquisitor.cpp @@ -134,6 +134,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_InquisitorCheckLand) DEFINE_ACTION_FUNCTION(AActor, A_TossArm) { PARAM_ACTION_PROLOGUE; + + AActor *foo = Spawn("InquisitorArm", self->PosPlusZ(24*FRACUNIT), ALLOW_REPLACE); foo->angle = self->angle - ANGLE_90 + (pr_inq.Random2() << 22); foo->velx = FixedMul (foo->Speed, finecosine[foo->angle >> ANGLETOFINESHIFT]) >> 3; foo->vely = FixedMul (foo->Speed, finesine[foo->angle >> ANGLETOFINESHIFT]) >> 3; diff --git a/src/g_strife/a_programmer.cpp b/src/g_strife/a_programmer.cpp index 35a429d04..a0aa24e24 100644 --- a/src/g_strife/a_programmer.cpp +++ b/src/g_strife/a_programmer.cpp @@ -129,6 +129,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpotLightning) DEFINE_ACTION_FUNCTION(AActor, A_SpawnProgrammerBase) { PARAM_ACTION_PROLOGUE; + + AActor *foo = Spawn("ProgrammerBase", self->PosPlusZ(24*FRACUNIT), ALLOW_REPLACE); if (foo != NULL) { foo->angle = self->angle + ANGLE_180 + (pr_prog.Random2() << 22); diff --git a/src/g_strife/a_spectral.cpp b/src/g_strife/a_spectral.cpp index f2ec6f273..765381e38 100644 --- a/src/g_strife/a_spectral.cpp +++ b/src/g_strife/a_spectral.cpp @@ -59,7 +59,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpectralLightning) PARAM_ACTION_PROLOGUE; AActor *flash; - fixed_t x, y; if (self->threshold != 0) --self->threshold; diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index e175b28a0..fc11ba433 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -718,6 +718,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_ItBurnsItBurns) DEFINE_ACTION_FUNCTION(AActor, A_DropFire) { PARAM_ACTION_PROLOGUE; + + AActor *drop = Spawn("FireDroplet", self->PosPlusZ(24*FRACUNIT), ALLOW_REPLACE); drop->velz = -FRACUNIT; P_RadiusAttack (self, self, 64, 64, NAME_Fire, 0); return 0; diff --git a/src/g_strife/a_thingstoblowup.cpp b/src/g_strife/a_thingstoblowup.cpp index 3691a639b..df6d76984 100644 --- a/src/g_strife/a_thingstoblowup.cpp +++ b/src/g_strife/a_thingstoblowup.cpp @@ -18,10 +18,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Bang4Cloud) { PARAM_ACTION_PROLOGUE; - fixed_t spawnx, spawny; - fixedvec3 pos = self->Vec3Offset((pr_bang4cloud.Random2() & 3) * 10240, (pr_bang4cloud.Random2() & 3) * 10240, 0); - Spawn("Bang4Cloud", pos, ALLOW_REPLACE); return 0; } diff --git a/src/p_local.h b/src/p_local.h index c739cf10a..d2e36a19a 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -134,7 +134,7 @@ enum EPuffFlags }; AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags = 0, AActor *vict = NULL); -inline AActor *P_SpawnPuff(AActor *source, const PClass *pufftype, const fixedvec3 &pos, angle_t dir, int updown, int flags = 0, AActor *vict = NULL) +inline AActor *P_SpawnPuff(AActor *source, PClassActor *pufftype, const fixedvec3 &pos, angle_t dir, int updown, int flags = 0, AActor *vict = NULL) { return P_SpawnPuff(source, pufftype, pos.x, pos.y, pos.z, dir, updown, flags, vict); } @@ -145,6 +145,7 @@ void P_RipperBlood (AActor *mo, AActor *bleeder); int P_GetThingFloorType (AActor *thing); void P_ExplodeMissile (AActor *missile, line_t *explodeline, AActor *target); +AActor *P_OldSpawnMissile(AActor *source, AActor *owner, AActor *dest, PClassActor *type); AActor *P_SpawnMissile (AActor* source, AActor* dest, PClassActor *type, AActor* owner = NULL); AActor *P_SpawnMissileZ (AActor* source, fixed_t z, AActor* dest, PClassActor *type); AActor *P_SpawnMissileXYZ (fixed_t x, fixed_t y, fixed_t z, AActor *source, AActor *dest, PClassActor *type, bool checkspawn = true, AActor *owner = NULL); From 98a9d7210a4e6df1bb263134e571165cdcf86758 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers <c.oelckers@zdoom.fake> Date: Wed, 20 Jan 2016 15:19:35 +0100 Subject: [PATCH 231/232] - fixed the definitions for script access to AActor::x, y, z. (Note: These should be made read only when real scripting becomes available!) --- src/thingdef/thingdef_data.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index f44e9b65f..8581ca8b2 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -632,9 +632,9 @@ void InitThingdef() symt.AddSymbol(new PField(NAME_TID, TypeSInt32, VARF_Native, myoffsetof(AActor,tid))); symt.AddSymbol(new PField(NAME_TIDtoHate, TypeSInt32, VARF_Native, myoffsetof(AActor,TIDtoHate))); symt.AddSymbol(new PField(NAME_WaterLevel, TypeSInt32, VARF_Native, myoffsetof(AActor,waterlevel))); - symt.AddSymbol(new PField(NAME_X, TypeFixed, VARF_Native, myoffsetof(AActor,x))); - symt.AddSymbol(new PField(NAME_Y, TypeFixed, VARF_Native, myoffsetof(AActor,y))); - symt.AddSymbol(new PField(NAME_Z, TypeFixed, VARF_Native, myoffsetof(AActor,z))); + symt.AddSymbol(new PField(NAME_X, TypeFixed, VARF_Native, myoffsetof(AActor,__pos.x))); // must remain read-only! + symt.AddSymbol(new PField(NAME_Y, TypeFixed, VARF_Native, myoffsetof(AActor,__pos.y))); // must remain read-only! + symt.AddSymbol(new PField(NAME_Z, TypeFixed, VARF_Native, myoffsetof(AActor,__pos.z))); // must remain read-only! symt.AddSymbol(new PField(NAME_VelX, TypeFixed, VARF_Native, myoffsetof(AActor,velx))); symt.AddSymbol(new PField(NAME_VelY, TypeFixed, VARF_Native, myoffsetof(AActor,vely))); symt.AddSymbol(new PField(NAME_VelZ, TypeFixed, VARF_Native, myoffsetof(AActor,velz))); From 1ac0d0690c07f7d5422b1def288372607e372b5e Mon Sep 17 00:00:00 2001 From: Randy Heit <rheit@users.noreply.github.com> Date: Thu, 21 Jan 2016 12:46:12 -0600 Subject: [PATCH 232/232] Re-remove testglobalvar from constants.txt so scripting branch runs again --- wadsrc/static/actors/constants.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index a88290451..f750772b1 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -510,7 +510,3 @@ enum CBF_SETTRACER = 1 << 3, //^ but with tracer. CBF_SETONPTR = 1 << 4, //Sets the pointer change on the actor doing the checking instead of self. }; - -// This is only here to provide one global variable for testing. -native int testglobalvar; -