From b45522734278767f20f117d47f230bfdaa463865 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 21 Oct 2008 18:10:50 +0000 Subject: [PATCH] - Added a proper function parser to the expression evaluator and converted sin/cos and action specials to use it. The old evaluator is gone now. - fixed some GCC problems with autosegs. SVN r1274 (trunk) --- docs/rh-log.txt | 5 + src/autosegs.h | 2 +- src/thingdef/thingdef_exp.cpp | 153 ++------------ src/thingdef/thingdef_exp.h | 107 ++++++---- src/thingdef/thingdef_expression.cpp | 293 +++++++++++++++++++++++++++ src/thingdef/thingdef_main.cpp | 7 + 6 files changed, 383 insertions(+), 184 deletions(-) diff --git a/docs/rh-log.txt b/docs/rh-log.txt index bcd58bde0..615eccf9d 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,3 +1,8 @@ +October 21, 2008 (Changes by Graf Zahl) +- Added a proper function parser to the expression evaluator and converted + sin/cos and action specials to use it. The old evaluator is gone now. +- fixed some GCC problems with autosegs. + October 20, 2008 - Game time is now frozen during screen wipes. This obsoletes the DEM_WIPEON and DEM_WIPEOFF commands. Fixes multimap demos desyncing when played back diff --git a/src/autosegs.h b/src/autosegs.h index 3c2b5d3e4..01069c51d 100644 --- a/src/autosegs.h +++ b/src/autosegs.h @@ -40,7 +40,7 @@ #define AREG_SECTION "__DATA,areg" #define CREG_SECTION "__DATA,creg" #define GREG_SECTION "__DATA,greg" -#define GREG_SECTION "__DATA,mreg" +#define MREG_SECTION "__DATA,mreg" #else #define AREG_SECTION "areg" #define CREG_SECTION "creg" diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index d58bc48ee..d7cd8d11e 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -1,7 +1,7 @@ /* ** thingdef_exp.cpp ** -** Expression parsing / runtime evaluating support +** Expression parsing for DECORATE ** **--------------------------------------------------------------------------- ** Copyright 2005 Jan Cholasta @@ -410,69 +410,27 @@ static FxExpression *ParseExpression0 (FScanner &sc, const PClass *cls) default: if (sc.CheckToken('(')) { - if (identifier == NAME_Sin) + FArgumentList *args = NULL; + try { - FxExpression *data = new FxExpression; - data->Type = EX_Sin; - data->ValueType = VAL_Float; - - data->Children[0] = ParseExpressionM (sc, cls); - - sc.MustGetToken(')'); - return data; - } - else if (identifier == NAME_Cos) - { - FxExpression *data = new FxExpression; - data->Type = EX_Cos; - data->ValueType = VAL_Float; - - data->Children[0] = ParseExpressionM (sc, cls); - - sc.MustGetToken(')'); - return data; - } - else - { - int specnum, min_args, max_args; - - // Check if this is an action special - specnum = P_FindLineSpecial (sc.String, &min_args, &max_args); - if (specnum != 0 && min_args >= 0) + if (!sc.CheckToken(')')) { - int i; - - FxExpression *data = new FxExpression, **left; - data->Type = EX_ActionSpecial; - data->Value.Int = specnum; - data->ValueType = VAL_Int; - - data->Children[0] = ParseExpressionM (sc, cls); - left = &data->Children[1]; - - for (i = 1; i < 5 && sc.CheckToken(','); ++i) + args = new FArgumentList; + do { - FxExpression *right = new FxExpression; - right->Type = EX_Right; - right->Children[0] = ParseExpressionM (sc, cls); - *left = right; - left = &right->Children[1]; + args->Push(ParseExpressionM (sc, cls)); + } - *left = NULL; + while (sc.CheckToken(',')); sc.MustGetToken(')'); - if (i < min_args) - sc.ScriptError ("Not enough arguments to action special"); - if (i > max_args) - sc.ScriptError ("Too many arguments to action special"); - - return data; - } - else - { - sc.ScriptError("Unknown function '%s'", identifier.GetChars()); } + return new FxFunctionCall(NULL, identifier, args, sc); + } + catch (...) + { + delete args; + throw; } - } else { @@ -489,84 +447,3 @@ static FxExpression *ParseExpression0 (FScanner &sc, const PClass *cls) } -ExpVal FxExpression::EvalExpression (AActor *self) -{ - ExpVal val; - - val.Type = VAL_Int; // Placate GCC - - switch (Type) - { - case EX_NOP: - assert (Type != EX_NOP); - val = Value; - break; - case EX_Sin: - { - ExpVal a = Children[0]->EvalExpression (self); - angle_t angle = (a.Type == VAL_Int) ? (a.Int * ANGLE_1) : angle_t(a.Float * ANGLE_1); - - val.Type = VAL_Float; - val.Float = FIXED2FLOAT (finesine[angle>>ANGLETOFINESHIFT]); - } - break; - - case EX_Cos: - { - ExpVal a = Children[0]->EvalExpression (self); - angle_t angle = (a.Type == VAL_Int) ? (a.Int * ANGLE_1) : angle_t(a.Float * ANGLE_1); - - val.Type = VAL_Float; - val.Float = FIXED2FLOAT (finecosine[angle>>ANGLETOFINESHIFT]); - } - break; - - case EX_ActionSpecial: - { - int parms[5] = { 0, 0, 0, 0 }; - int i = 0; - FxExpression *parm = this; - - while (parm != NULL && i < 5) - { - ExpVal val = parm->Children[0]->EvalExpression (self); - if (val.Type == VAL_Int) - { - parms[i] = val.Int; - } - else - { - parms[i] = (int)val.Float; - } - i++; - parm = parm->Children[1]; - } - - val.Type = VAL_Int; - val.Int = LineSpecials[Value.Int] (NULL, self, false, - parms[0], parms[1], parms[2], parms[3], parms[4]); - } - break; - - case EX_Right: - // This should never be a top-level expression. - assert (Type != EX_Right); - break; - } - - return val; -} - - -bool FxExpression::isConstant() const -{ - return false; -} - -FxExpression *FxExpression::Resolve(FCompileContext &ctx) -{ - if (Children[0]) Children[0] = Children[0]->Resolve(ctx); - if (Children[1]) Children[1] = Children[1]->Resolve(ctx); - return this; -} - diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 9ec779acb..3bcb40c3f 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -133,24 +133,6 @@ struct FCompileContext // //========================================================================== -enum ExpOp -{ - EX_NOP, - - EX_Var, - - EX_Sin, // sin (angle) - EX_Cos, // cos (angle) - EX_ActionSpecial, - EX_Right, -}; - -//========================================================================== -// -// -// -//========================================================================== - struct ExpVal { ExpValType Type; @@ -192,34 +174,11 @@ struct ExpVal struct FxExpression { - FxExpression () - { - isresolved = false; - ValueType = VAL_Unknown; - Type = EX_NOP; - Value.Type = VAL_Int; - Value.Int = 0; - for (int i = 0; i < 2; i++) - Children[i] = NULL; - } - virtual ~FxExpression () - { - for (int i = 0; i < 2; i++) - { - if (Children[i]) - { - delete Children[i]; - } - } - } - protected: FxExpression(const FScriptPosition &pos) { isresolved = false; ScriptPosition = pos; - for (int i = 0; i < 2; i++) - Children[i] = NULL; } public: virtual FxExpression *Resolve(FCompileContext &ctx); @@ -233,10 +192,6 @@ public: virtual bool isConstant() const; virtual void RequestAddress(); - int Type; - ExpVal Value; - FxExpression *Children[2]; - FScriptPosition ScriptPosition; FExpressionType ValueType; protected: @@ -687,6 +642,68 @@ public: }; +//========================================================================== +// +// FxFunctionCall +// +//========================================================================== + +typedef TDeletingArray FArgumentList; + +class FxFunctionCall : public FxExpression +{ + FxExpression *Self; + FName MethodName; + FArgumentList *ArgList; + +public: + + FxFunctionCall(FxExpression *self, FName methodname, FArgumentList *args, const FScriptPosition &pos); + ~FxFunctionCall(); + FxExpression *Resolve(FCompileContext&); +}; + + +//========================================================================== +// +// FxActionSpecialCall +// +//========================================================================== + +class FxActionSpecialCall : public FxExpression +{ + FxExpression *Self; + int Special; + FArgumentList *ArgList; + +public: + + FxActionSpecialCall(FxExpression *self, int special, FArgumentList *args, const FScriptPosition &pos); + ~FxActionSpecialCall(); + FxExpression *Resolve(FCompileContext&); + ExpVal EvalExpression (AActor *self); +}; + +//========================================================================== +// +// FxGlobalFunctionCall +// +//========================================================================== + +class FxGlobalFunctionCall : public FxExpression +{ + FName Name; + FArgumentList *ArgList; + +public: + + FxGlobalFunctionCall(FName fname, FArgumentList *args, const FScriptPosition &pos); + ~FxGlobalFunctionCall(); + FxExpression *Resolve(FCompileContext&); + ExpVal EvalExpression (AActor *self); +}; + + FxExpression *ParseExpression (FScanner &sc, PClass *cls); diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index a9ed0e2c6..980a56332 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -51,6 +51,7 @@ #include "thingdef_exp.h" #include "autosegs.h" +extern int thingdef_terminate; int testglobalvar = 1337; // just for having one global variable to test with DEFINE_GLOBAL_VARIABLE(testglobalvar) @@ -221,6 +222,7 @@ void STACK_ARGS FScriptPosition::Message (int severity, const char *message, ... break; case MSG_ERROR: + thingdef_terminate++; type = "error"; break; @@ -240,6 +242,45 @@ void STACK_ARGS FScriptPosition::Message (int severity, const char *message, ... } +//========================================================================== +// +// +// +//========================================================================== + +ExpVal FxExpression::EvalExpression (AActor *self) +{ + I_Error("Unresolved expression found"); + ExpVal val; + + val.Type = VAL_Int; + val.Int = 0; + return val; +} + + +//========================================================================== +// +// +// +//========================================================================== + +bool FxExpression::isConstant() const +{ + return false; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxExpression::Resolve(FCompileContext &ctx) +{ + return this; +} + //========================================================================== // // @@ -2112,4 +2153,256 @@ ExpVal FxArrayElement::EvalExpression (AActor *self) } +//========================================================================== +// +// +// +//========================================================================== +FxFunctionCall::FxFunctionCall(FxExpression *self, FName methodname, FArgumentList *args, const FScriptPosition &pos) +: FxExpression(pos) +{ + Self = self; + MethodName = methodname; + ArgList = args; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxFunctionCall::~FxFunctionCall() +{ + SAFE_DELETE(Self); + SAFE_DELETE(ArgList); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) +{ + // There's currently only 2 global functions. + // This will have to change later! + if (MethodName == NAME_Sin || MethodName == NAME_Cos) + { + if (Self != NULL) + { + ScriptPosition.Message(MSG_ERROR, "Global variables cannot have a self pointer"); + delete this; + return NULL; + } + FxExpression *x = new FxGlobalFunctionCall(MethodName, ArgList, ScriptPosition); + ArgList = NULL; + delete this; + return x->Resolve(ctx); + } + + int min, max; + int special = P_FindLineSpecial(MethodName.GetChars(), &min, &max); + if (special > 0 && min >= 0) + { + int paramcount = ArgList? ArgList->Size() : 0; + if (paramcount < min) + { + ScriptPosition.Message(MSG_ERROR, "Not enough parameters for '%s' (expected %d, got %d)", + MethodName.GetChars(), min, paramcount); + delete this; + return NULL; + } + else if (paramcount > max) + { + ScriptPosition.Message(MSG_ERROR, "too many parameters for '%s' (expected %d, got %d)", + MethodName.GetChars(), max, paramcount); + delete this; + return NULL; + } + FxExpression *x = new FxActionSpecialCall(Self, special, ArgList, ScriptPosition); + ArgList = NULL; + delete this; + return x->Resolve(ctx); + } + + ScriptPosition.Message(MSG_ERROR, "Call to unknown function '%s'", MethodName.GetChars()); + delete this; + return NULL; +} + + +//========================================================================== +// +// +// +//========================================================================== + +FxActionSpecialCall::FxActionSpecialCall(FxExpression *self, int special, FArgumentList *args, const FScriptPosition &pos) +: FxExpression(pos) +{ + Self = self; + Special = special; + ArgList = args; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxActionSpecialCall::~FxActionSpecialCall() +{ + SAFE_DELETE(Self); + SAFE_DELETE(ArgList); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxActionSpecialCall::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 ((*ArgList)[i]->ValueType != VAL_Int) + { + if (ctx.lax && ((*ArgList)[i]->ValueType == VAL_Float)) + { + (*ArgList)[i] = new FxIntCast((*ArgList)[i]); + } + else + { + ScriptPosition.Message(MSG_ERROR, "Integer expected for parameter %d", i); + failed = true; + } + } + } + if (failed) + { + delete this; + return NULL; + } + } + ValueType = VAL_Int; + return this; +} + + +//========================================================================== +// +// +// +//========================================================================== + +ExpVal FxActionSpecialCall::EvalExpression (AActor *self) +{ + int v[5] = {0,0,0,0,0}; + + if (Self != NULL) + { + self = Self->EvalExpression(self).GetPointer(); + } + + if (ArgList != NULL) + { + for(unsigned i = 0; i < ArgList->Size(); i++) + { + v[i] = (*ArgList)[i]->EvalExpression(self).GetInt(); + } + } + ExpVal ret; + ret.Type = VAL_Int; + ret.Int = LineSpecials[Special](NULL, self, false, v[0], v[1], v[2], v[3], v[4]); + return ret; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxGlobalFunctionCall::FxGlobalFunctionCall(FName fname, FArgumentList *args, const FScriptPosition &pos) +: FxExpression(pos) +{ + Name = fname; + ArgList = args; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxGlobalFunctionCall::~FxGlobalFunctionCall() +{ + SAFE_DELETE(ArgList); +} + +//========================================================================== +// +// // so far just a quick hack to handle sin and cos +// +//========================================================================== + +FxExpression *FxGlobalFunctionCall::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + + if (ArgList == NULL || ArgList->Size() != 1) + { + ScriptPosition.Message(MSG_ERROR, "%s only has one parameter", Name.GetChars()); + delete this; + return NULL; + } + + (*ArgList)[0] = (*ArgList)[0]->Resolve(ctx); + if ((*ArgList)[0] == NULL) + { + delete this; + return NULL; + } + + if (!(*ArgList)[0]->ValueType.isNumeric()) + { + ScriptPosition.Message(MSG_ERROR, "numeric value expected for parameter"); + delete this; + return NULL; + } + ValueType = VAL_Float; + return this; +} + + +//========================================================================== +// +// +// +//========================================================================== + +ExpVal FxGlobalFunctionCall::EvalExpression (AActor *self) +{ + double v = (*ArgList)[0]->EvalExpression(self).GetFloat(); + ExpVal ret; + ret.Type = VAL_Float; + + // shall we use the CRT's sin and cos functions? + angle_t angle = angle_t(v * ANGLE_90/90.); + if (Name == NAME_Sin) ret.Float = FIXED2FLOAT (finesine[angle>>ANGLETOFINESHIFT]); + else ret.Float = FIXED2FLOAT (finecosine[angle>>ANGLETOFINESHIFT]); + return ret; +} \ No newline at end of file diff --git a/src/thingdef/thingdef_main.cpp b/src/thingdef/thingdef_main.cpp index 9469ec3cc..c33961a00 100644 --- a/src/thingdef/thingdef_main.cpp +++ b/src/thingdef/thingdef_main.cpp @@ -43,6 +43,7 @@ #include "s_sound.h" #include "cmdlib.h" #include "thingdef.h" +#include "i_system.h" // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- @@ -54,6 +55,8 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def); // STATIC FUNCTION PROTOTYPES -------------------------------------------- PSymbolTable GlobalSymbols; +int thingdef_terminate; + //========================================================================== // // ParseDecorate @@ -154,6 +157,10 @@ void LoadDecorations () FScanner sc(lump); ParseDecorate (sc); } + if (thingdef_terminate) + { + I_Error("%d errors found", thingdef_terminate); + } FinishThingdef(); }