From 7312e6a62167e6aca360410da902b621087afb70 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 18 Oct 2008 17:17:44 +0000 Subject: [PATCH] - Added a global symbol table and changed DECORATE parser to put its global symbols there instead of into AActor. - Changed the expression evaluator's floating point precision to double. - Started rewriting the DECORATE expression evaluator to allow more flexibility. All the operators use the new functionality but functions, variables and constants are yet to be redone. While doing this rewrite I noticed that random2 was always evaluated as const. This got fixed automatically. SVN r1264 (trunk) --- docs/rh-log.txt | 10 + src/CMakeLists.txt | 1 + src/namedef.h | 1 + src/p_lnspec.cpp | 2 +- src/thingdef/thingdef.h | 2 +- src/thingdef/thingdef_exp.cpp | 1390 +++++++------------------- src/thingdef/thingdef_exp.h | 584 +++++++++++ src/thingdef/thingdef_expression.cpp | 1377 +++++++++++++++++++++++++ src/thingdef/thingdef_main.cpp | 5 +- src/thingdef/thingdef_parse.cpp | 19 +- zdoom.vcproj | 8 + 11 files changed, 2337 insertions(+), 1062 deletions(-) create mode 100644 src/thingdef/thingdef_exp.h create mode 100644 src/thingdef/thingdef_expression.cpp diff --git a/docs/rh-log.txt b/docs/rh-log.txt index a3373ad5f6..4ee417adf7 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,3 +1,13 @@ +October 18, 2008 (Changes by Graf Zahl) +- Added a global symbol table and changed DECORATE parser to put its global + symbols there instead of into AActor. +- Changed the expression evaluator's floating point precision to double. +- Started rewriting the DECORATE expression evaluator to allow more flexibility. + All the operators use the new functionality but functions, variables and + constants are yet to be redone. + While doing this rewrite I noticed that random2 was always evaluated as const. + This got fixed automatically. + October 13, 2008 - This may or may not be a problem, but GCC warned that FStateDefinitions:: AddStateDefines() does not initialize def.FStateDefine::DefineFlags, so diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d1bd7bd4cf..ff346fd6a8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -625,6 +625,7 @@ add_executable( zdoom WIN32 thingdef/thingdef.cpp thingdef/thingdef_codeptr.cpp thingdef/thingdef_exp.cpp + thingdef/thingdef_expression.cpp thingdef/thingdef_main.cpp thingdef/thingdef_parse.cpp thingdef/thingdef_properties.cpp diff --git a/src/namedef.h b/src/namedef.h index ab933d26ec..1d9c8750fc 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -254,6 +254,7 @@ xx(Z) xx(MomX) xx(MomY) xx(MomZ) +xx(Abs) // Various actor names which are used internally xx(MapSpot) diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 961c0e078c..52d34ee8f3 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -3162,7 +3162,7 @@ struct FLineSpecial { const char *name; BYTE number; - BYTE min_args; + SBYTE min_args; SBYTE max_args; }; diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index 6a47456c86..0b2b3d9f3d 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -183,7 +183,7 @@ int ParseExpression (FScanner &sc, bool _not, PClass *cls); bool IsExpressionConst(int id); int EvalExpressionI (int id, AActor *self, const PClass *cls=NULL); -float EvalExpressionF (int id, AActor *self, const PClass *cls=NULL); +double EvalExpressionF (int id, AActor *self, const PClass *cls=NULL); fixed_t EvalExpressionFix (int id, AActor *self, const PClass *cls=NULL); diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index 296dc93ba8..680ac39f39 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -47,66 +47,17 @@ #include "a_pickups.h" #include "thingdef.h" #include "p_lnspec.h" - -void InitExpressions (); -void ClearExpressions (); +#include "doomstat.h" +#include "thingdef_exp.h" FRandom pr_exrandom ("EX_Random"); -enum ExpOp -{ - EX_NOP, +extern PSymbolTable GlobalSymbols; - EX_Const, - EX_Var, - EX_Compl, // ~exp - EX_Not, // !exp -// EX_Plus, // +exp - EX_Minus, // -exp - EX_Mul, // exp * exp - EX_Div, // exp / exp - EX_Mod, // exp % exp - EX_Add, // exp + exp - EX_Sub, // exp - exp - EX_LShift, // exp << exp - EX_RShift, // exp >> exp - EX_LT, // exp < exp - EX_GT, // exp > exp - EX_LE, // exp <= exp - EX_GE, // exp >= exp - EX_Eq, // exp == exp - EX_NE, // exp != exp - EX_And, // exp & exp - EX_Xor, // exp ^ exp - EX_Or, // exp | exp - EX_LogAnd, // exp && exp - EX_LogOr, // exp || exp - EX_Cond, // exp ? exp : exp - EX_Random, // random (min, max) - EX_Random2, // random2 ([mask]) - EX_Sin, // sin (angle) - EX_Cos, // cos (angle) - EX_ActionSpecial, - EX_Right, -}; -enum ExpValType -{ - VAL_Int, - VAL_Float, -}; -struct ExpVal -{ - ExpValType Type; - union - { - int Int; - float Float; - }; -}; typedef ExpVal (*ExpVarGet) (AActor *, int); @@ -122,7 +73,7 @@ ExpVal GetAngle (AActor *actor, int id) { ExpVal val; val.Type = VAL_Float; - val.Float = (float)actor->angle / ANGLE_1; + val.Float = (double)actor->angle / ANGLE_1; return val; } @@ -162,7 +113,7 @@ ExpVal GetPitch (AActor *actor, int id) { ExpVal val; val.Type = VAL_Float; - val.Float = (float)actor->pitch / ANGLE_1; + val.Float = (double)actor->pitch / ANGLE_1; return val; } @@ -251,448 +202,271 @@ static struct FExpVar ENamedName name; // identifier int array; // array size (0 if not an array) ExpVarGet get; + int ValueType; } ExpVars[] = { - { NAME_Alpha, 0, GetAlpha }, - { NAME_Angle, 0, GetAngle }, - { NAME_Args, 5, GetArgs }, - { NAME_CeilingZ, 0, GetCeilingZ }, - { NAME_FloorZ, 0, GetFloorZ }, - { NAME_Health, 0, GetHealth }, - { NAME_Pitch, 0, GetPitch }, - { NAME_Special, 0, GetSpecial }, - { NAME_TID, 0, GetTID }, - { NAME_TIDtoHate, 0, GetTIDToHate }, - { NAME_WaterLevel, 0, GetWaterLevel }, - { NAME_X, 0, GetX }, - { NAME_Y, 0, GetY }, - { NAME_Z, 0, GetZ }, - { NAME_MomX, 0, GetMomX }, - { NAME_MomY, 0, GetMomY }, - { NAME_MomZ, 0, GetMomZ }, + { NAME_Alpha, 0, GetAlpha, VAL_Float }, + { NAME_Angle, 0, GetAngle, VAL_Float }, + { NAME_Args, 5, GetArgs, VAL_Int }, + { NAME_CeilingZ, 0, GetCeilingZ, VAL_Float }, + { NAME_FloorZ, 0, GetFloorZ, VAL_Float }, + { NAME_Health, 0, GetHealth, VAL_Int }, + { NAME_Pitch, 0, GetPitch, VAL_Float }, + { NAME_Special, 0, GetSpecial, VAL_Int }, + { NAME_TID, 0, GetTID, VAL_Int }, + { NAME_TIDtoHate, 0, GetTIDToHate, VAL_Int }, + { NAME_WaterLevel, 0, GetWaterLevel, VAL_Int }, + { NAME_X, 0, GetX, VAL_Float }, + { NAME_Y, 0, GetY, VAL_Float }, + { NAME_Z, 0, GetZ, VAL_Float }, + { NAME_MomX, 0, GetMomX, VAL_Float }, + { NAME_MomY, 0, GetMomY, VAL_Float }, + { NAME_MomZ, 0, GetMomZ, VAL_Float }, }; -struct ExpData; -static ExpVal EvalExpression (ExpData *data, AActor *self, const PClass *cls); -struct ExpData -{ - ExpData () - { - Type = EX_NOP; - Value.Type = VAL_Int; - Value.Int = 0; - RNG = NULL; - for (int i = 0; i < 2; i++) - Children[i] = NULL; - } - ~ExpData () - { - for (int i = 0; i < 2; i++) - { - if (Children[i]) - { - delete Children[i]; - } - } - } - // Try to evaluate constant expression - void EvalConst (const PClass *cls) - { - if (Type == EX_NOP || Type == EX_Const || Type == EX_Var) - { - return; - } - else if (Type == EX_Compl || Type == EX_Not || /*Type == EX_Plus || */Type == EX_Minus) - { - if (Children[0]->Type == EX_Const) - { - Value = EvalExpression (this, NULL, cls); - Type = EX_Const; - } - } - else if (Type == EX_Cond) - { - if (Children[0]->Type == EX_Const) - { - bool cond = (Children[0]->Value.Type == VAL_Int) ? (Children[0]->Value.Int != 0) : (Children[0]->Value.Float != 0); - ExpData *data = Children[1]->Children[cond]; - delete Children[1]->Children[!cond]; - delete Children[1]; - delete Children[0]; - - Type = data->Type; - Value = data->Value; - for (int i = 0; i < 2; i++) - { - Children[i] = data->Children[i]; - data->Children[i] = NULL; - } - - delete data; - } - } - else if (Type != EX_Random && Type != EX_Sin && Type != EX_Cos && Type != EX_ActionSpecial) - { - if (Children[0]->Type == EX_Const && Children[1]->Type == EX_Const) - { - Value = EvalExpression (this, NULL, NULL); - Type = EX_Const; - delete Children[0]; Children[0] = NULL; - delete Children[1]; Children[1] = NULL; - } - } - } - bool Compare (ExpData *other) - { - if (!other) - return false; - - if (Type != other->Type || - Value.Type != other->Value.Type || - Value.Float != other->Value.Float || - RNG != other->RNG) - { - return false; - } - - for (int i = 0; i < 2; i++) - { - if (Children[i] && !Children[i]->Compare (other->Children[i])) - return false; - } - - return true; - } - - ExpOp Type; - ExpVal Value; - ExpData *Children[2]; - FRandom *RNG; // only used by random and random2 -}; - -TArray StateExpressions; +TDeletingArray StateExpressions; // // ParseExpression // [GRB] Parses an expression and stores it into Expression array // -static ExpData *ParseExpressionM (FScanner &sc, const PClass *cls); -static ExpData *ParseExpressionL (FScanner &sc, const PClass *cls); -static ExpData *ParseExpressionK (FScanner &sc, const PClass *cls); -static ExpData *ParseExpressionJ (FScanner &sc, const PClass *cls); -static ExpData *ParseExpressionI (FScanner &sc, const PClass *cls); -static ExpData *ParseExpressionH (FScanner &sc, const PClass *cls); -static ExpData *ParseExpressionG (FScanner &sc, const PClass *cls); -static ExpData *ParseExpressionF (FScanner &sc, const PClass *cls); -static ExpData *ParseExpressionE (FScanner &sc, const PClass *cls); -static ExpData *ParseExpressionD (FScanner &sc, const PClass *cls); -static ExpData *ParseExpressionC (FScanner &sc, const PClass *cls); -static ExpData *ParseExpressionB (FScanner &sc, const PClass *cls); -static ExpData *ParseExpressionA (FScanner &sc, const PClass *cls); +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); -int ParseExpression (FScanner &sc, bool _not, PClass *cls) +FxExpression *ParseExpression (FScanner &sc, PClass *cls) { - static bool inited=false; - - if (!inited) - { - InitExpressions (); - atterm (ClearExpressions); - inited=true; - } + FxExpression *data = ParseExpressionM (sc, cls); - ExpData *data = ParseExpressionM (sc, cls); - - for (unsigned int i = 0; i < StateExpressions.Size (); i++) - { - if (StateExpressions[i]->Compare (data)) - { - delete data; - return i; - } - } - - return StateExpressions.Push (data); -} - -static ExpData *ParseExpressionM (FScanner &sc, const PClass *cls) -{ - ExpData *tmp = ParseExpressionL (sc, cls); - - if (sc.CheckToken('?')) - { - ExpData *data = new ExpData; - data->Type = EX_Cond; - data->Children[0] = tmp; - ExpData *choices = new ExpData; - data->Children[1] = choices; - choices->Type = EX_Right; - choices->Children[0] = ParseExpressionM (sc, cls); - sc.MustGetToken(':'); - choices->Children[1] = ParseExpressionM (sc, cls); - data->EvalConst (cls); - return data; - } - else - { - return tmp; - } -} - -static ExpData *ParseExpressionL (FScanner &sc, const PClass *cls) -{ - ExpData *tmp = ParseExpressionK (sc, cls); - - while (sc.CheckToken(TK_OrOr)) - { - ExpData *right = ParseExpressionK (sc, cls); - ExpData *data = new ExpData; - data->Type = EX_LogOr; - data->Children[0] = tmp; - data->Children[1] = right; - data->EvalConst (cls); - tmp = data; - } - return tmp; -} - -static ExpData *ParseExpressionK (FScanner &sc, const PClass *cls) -{ - ExpData *tmp = ParseExpressionJ (sc, cls); - - while (sc.CheckToken(TK_AndAnd)) - { - ExpData *right = ParseExpressionJ (sc, cls); - ExpData *data = new ExpData; - data->Type = EX_LogAnd; - data->Children[0] = tmp; - data->Children[1] = right; - data->EvalConst (cls); - tmp = data; - } - return tmp; -} - -static ExpData *ParseExpressionJ (FScanner &sc, const PClass *cls) -{ - ExpData *tmp = ParseExpressionI (sc, cls); - - while (sc.CheckToken('|')) - { - ExpData *right = ParseExpressionI (sc, cls); - ExpData *data = new ExpData; - data->Type = EX_Or; - data->Children[0] = tmp; - data->Children[1] = right; - data->EvalConst (cls); - tmp = data; - } - return tmp; -} - -static ExpData *ParseExpressionI (FScanner &sc, const PClass *cls) -{ - ExpData *tmp = ParseExpressionH (sc, cls); - - while (sc.CheckToken('^')) - { - ExpData *right = ParseExpressionH (sc, cls); - ExpData *data = new ExpData; - data->Type = EX_Xor; - data->Children[0] = tmp; - data->Children[1] = right; - data->EvalConst (cls); - tmp = data; - } - return tmp; -} - -static ExpData *ParseExpressionH (FScanner &sc, const PClass *cls) -{ - ExpData *tmp = ParseExpressionG (sc, cls); - - while (sc.CheckToken('&')) - { - ExpData *right = ParseExpressionG (sc, cls); - ExpData *data = new ExpData; - data->Type = EX_And; - data->Children[0] = tmp; - data->Children[1] = right; - data->EvalConst (cls); - tmp = data; - } - return tmp; -} - -static ExpData *ParseExpressionG (FScanner &sc, const PClass *cls) -{ - ExpData *tmp = ParseExpressionF (sc, cls); - - while (sc.GetToken() && (sc.TokenType == TK_Eq || sc.TokenType == TK_Neq)) - { - int token = sc.TokenType; - ExpData *right = ParseExpressionF (sc, cls); - ExpData *data = new ExpData; - data->Type = token == TK_Eq? EX_Eq : EX_NE; - data->Children[0] = tmp; - data->Children[1] = right; - data->EvalConst (cls); - tmp = data; - } - if (!sc.End) sc.UnGet(); - return tmp; -} - -static ExpData *ParseExpressionF (FScanner &sc, const PClass *cls) -{ - ExpData *tmp = ParseExpressionE (sc, cls); - - while (sc.GetToken() && (sc.TokenType == '<' || sc.TokenType == '>' || sc.TokenType == TK_Leq || sc.TokenType == TK_Geq)) - { - int token = sc.TokenType; - ExpData *right = ParseExpressionE (sc, cls); - ExpData *data = new ExpData; - data->Type = token == '<' ? EX_LT : token == '>' ? EX_GT : token == TK_Leq? EX_LE : EX_GE; - data->Children[0] = tmp; - data->Children[1] = right; - data->EvalConst (cls); - tmp = data; - } - if (!sc.End) sc.UnGet(); - return tmp; -} - -static ExpData *ParseExpressionE (FScanner &sc, const PClass *cls) -{ - ExpData *tmp = ParseExpressionD (sc, cls); - - while (sc.GetToken() && (sc.TokenType == TK_LShift || sc.TokenType == TK_RShift)) - { - int token = sc.TokenType; - ExpData *right = ParseExpressionD (sc, cls); - ExpData *data = new ExpData; - data->Type = token == TK_LShift? EX_LShift : EX_RShift; - data->Children[0] = tmp; - data->Children[1] = right; - data->EvalConst (cls); - tmp = data; - } - if (!sc.End) sc.UnGet(); - return tmp; -} - -static ExpData *ParseExpressionD (FScanner &sc, const PClass *cls) -{ - ExpData *tmp = ParseExpressionC (sc, cls); - - while (sc.GetToken() && (sc.TokenType == '+' || sc.TokenType == '-')) - { - int token = sc.TokenType; - ExpData *right = ParseExpressionC (sc, cls); - ExpData *data = new ExpData; - data->Type = token == '+'? EX_Add : EX_Sub; - data->Children[0] = tmp; - data->Children[1] = right; - data->EvalConst (cls); - tmp = data; - } - if (!sc.End) sc.UnGet(); - return tmp; -} - -static ExpData *ParseExpressionC (FScanner &sc, const PClass *cls) -{ - ExpData *tmp = ParseExpressionB (sc, cls); - - while (sc.GetToken() && (sc.TokenType == '*' || sc.TokenType == '/' || sc.TokenType == '%')) - { - int token = sc.TokenType; - ExpData *right = ParseExpressionB (sc, cls); - ExpData *data = new ExpData; - data->Type = token == '*'? EX_Mul : token == '/'? EX_Div : EX_Mod; - data->Children[0] = tmp; - data->Children[1] = right; - data->EvalConst (cls); - tmp = data; - } - if (!sc.End) sc.UnGet(); - return tmp; -} - -static ExpData *ParseExpressionB (FScanner &sc, const PClass *cls) -{ - ExpData *data = new ExpData; - - if (sc.CheckToken('~')) - { - data->Type = EX_Compl; - } - else if (sc.CheckToken('!')) - { - data->Type = EX_Not; - } - else if (sc.CheckToken('-')) - { - data->Type = EX_Minus; - } - else - { - sc.CheckToken('+'); - delete data; - return ParseExpressionA (sc, cls); - } - - data->Children[0] = ParseExpressionA (sc, cls); - data->EvalConst (cls); + FCompileContext ctx; + ctx.cls = cls; + data = data->Resolve(ctx); return data; } -static ExpData *ParseExpressionA (FScanner &sc, const PClass *cls) + +int ParseExpression (FScanner &sc, bool _not, PClass *cls) { + if (StateExpressions.Size()==0) + { + // StateExpressions[0] always is const 0; + FxExpression *data = new FxConstant(0, FScriptPosition()); + StateExpressions.Push (data); + } + + FxExpression *data = ParseExpression (sc, cls); + return StateExpressions.Push (data); +} + +static FxExpression *ParseExpressionM (FScanner &sc, const PClass *cls) +{ + FxExpression *condition = ParseExpressionL (sc, cls); + + if (sc.CheckToken('?')) + { + FxExpression *truex = ParseExpressionM (sc, cls); + sc.MustGetToken(':'); + FxExpression *falsex = ParseExpressionM (sc, cls); + return new FxConditional(condition, truex, falsex); + } + else + { + return condition; + } +} + +static FxExpression *ParseExpressionL (FScanner &sc, const PClass *cls) +{ + FxExpression *tmp = ParseExpressionK (sc, cls); + + while (sc.CheckToken(TK_OrOr)) + { + FxExpression *right = ParseExpressionK (sc, cls); + tmp = new FxBinaryLogical(TK_OrOr, tmp, right); + } + return tmp; +} + +static FxExpression *ParseExpressionK (FScanner &sc, const PClass *cls) +{ + FxExpression *tmp = ParseExpressionJ (sc, cls); + + while (sc.CheckToken(TK_AndAnd)) + { + FxExpression *right = ParseExpressionJ (sc, cls); + tmp = new FxBinaryLogical(TK_AndAnd, tmp, right); + } + return tmp; +} + +static FxExpression *ParseExpressionJ (FScanner &sc, const PClass *cls) +{ + FxExpression *tmp = ParseExpressionI (sc, cls); + + while (sc.CheckToken('|')) + { + FxExpression *right = ParseExpressionI (sc, cls); + tmp = new FxBinaryInt('|', tmp, right); + } + return tmp; +} + +static FxExpression *ParseExpressionI (FScanner &sc, const PClass *cls) +{ + FxExpression *tmp = ParseExpressionH (sc, cls); + + while (sc.CheckToken('^')) + { + FxExpression *right = ParseExpressionH (sc, cls); + tmp = new FxBinaryInt('^', tmp, right); + } + return tmp; +} + +static FxExpression *ParseExpressionH (FScanner &sc, const PClass *cls) +{ + FxExpression *tmp = ParseExpressionG (sc, cls); + + while (sc.CheckToken('&')) + { + FxExpression *right = ParseExpressionG (sc, cls); + tmp = new FxBinaryInt('&', tmp, right); + } + return tmp; +} + +static FxExpression *ParseExpressionG (FScanner &sc, const PClass *cls) +{ + FxExpression *tmp = ParseExpressionF (sc, cls); + + while (sc.GetToken() && (sc.TokenType == TK_Eq || sc.TokenType == TK_Neq)) + { + int token = sc.TokenType; + FxExpression *right = ParseExpressionF (sc, cls); + tmp = new FxCompareEq(token, tmp, right); + } + if (!sc.End) sc.UnGet(); + return tmp; +} + +static FxExpression *ParseExpressionF (FScanner &sc, const PClass *cls) +{ + FxExpression *tmp = ParseExpressionE (sc, cls); + + while (sc.GetToken() && (sc.TokenType == '<' || sc.TokenType == '>' || sc.TokenType == TK_Leq || sc.TokenType == TK_Geq)) + { + int token = sc.TokenType; + FxExpression *right = ParseExpressionE (sc, cls); + tmp = new FxCompareRel(token, tmp, right); + } + if (!sc.End) sc.UnGet(); + return tmp; +} + +static FxExpression *ParseExpressionE (FScanner &sc, const PClass *cls) +{ + FxExpression *tmp = ParseExpressionD (sc, cls); + + while (sc.GetToken() && (sc.TokenType == TK_LShift || sc.TokenType == TK_RShift || sc.TokenType == TK_URShift)) + { + int token = sc.TokenType; + FxExpression *right = ParseExpressionD (sc, cls); + tmp = new FxBinaryInt(token, tmp, right); + } + if (!sc.End) sc.UnGet(); + return tmp; +} + +static FxExpression *ParseExpressionD (FScanner &sc, const PClass *cls) +{ + FxExpression *tmp = ParseExpressionC (sc, cls); + + while (sc.GetToken() && (sc.TokenType == '+' || sc.TokenType == '-')) + { + int token = sc.TokenType; + FxExpression *right = ParseExpressionC (sc, cls); + tmp = new FxAddSub(token, tmp, right); + } + if (!sc.End) sc.UnGet(); + return tmp; +} + +static FxExpression *ParseExpressionC (FScanner &sc, const PClass *cls) +{ + FxExpression *tmp = ParseExpressionB (sc, cls); + + while (sc.GetToken() && (sc.TokenType == '*' || sc.TokenType == '/' || sc.TokenType == '%')) + { + int token = sc.TokenType; + FxExpression *right = ParseExpressionB (sc, cls); + tmp = new FxMulDiv(token, tmp, right); + } + if (!sc.End) sc.UnGet(); + return tmp; +} + +static FxExpression *ParseExpressionB (FScanner &sc, const PClass *cls) +{ + sc.GetToken(); + switch(sc.TokenType) + { + case '~': + return new FxUnaryNotBitwise(ParseExpressionA (sc, cls)); + + case '!': + return new FxUnaryNotBoolean(ParseExpressionA (sc, cls)); + + case '-': + return new FxMinusSign(ParseExpressionA (sc, cls)); + + case '+': + return new FxPlusSign(ParseExpressionA (sc, cls)); + + default: + sc.UnGet(); + return ParseExpressionA (sc, cls); + } +} + + +static FxExpression *ParseExpressionA (FScanner &sc, const PClass *cls) +{ + FScriptPosition scpos(sc); if (sc.CheckToken('(')) { - ExpData *data = ParseExpressionM (sc, cls); + FxExpression *data = ParseExpressionM (sc, cls); sc.MustGetToken(')'); return data; } else if (sc.CheckToken(TK_True)) { - ExpData *data = new ExpData; - data->Type = EX_Const; - data->Value.Type = VAL_Int; - data->Value.Int = 1; - - return data; + return new FxConstant(1, scpos); } else if (sc.CheckToken(TK_False)) { - ExpData *data = new ExpData; - data->Type = EX_Const; - data->Value.Type = VAL_Int; - data->Value.Int = 0; - - return data; + return new FxConstant(0, scpos); } else if (sc.CheckToken(TK_IntConst)) { - ExpData *data = new ExpData; - data->Type = EX_Const; - data->Value.Type = VAL_Int; - data->Value.Int = sc.Number; - - return data; + return new FxConstant(sc.Number, scpos); } else if (sc.CheckToken(TK_FloatConst)) { - ExpData *data = new ExpData; - data->Type = EX_Const; - data->Value.Type = VAL_Float; - data->Value.Float = sc.Float; - - return data; + return new FxConstant(sc.Float, scpos); } + /* else if (sc.CheckToken(TK_Class)) { // Accept class'SomeClassName'.SomeConstant @@ -707,7 +481,7 @@ static ExpData *ParseExpressionA (FScanner &sc, const PClass *cls) PSymbol *sym = cls->Symbols.FindSymbol (sc.String, true); if (sym != NULL && sym->SymbolType == SYM_Const) { - ExpData *data = new ExpData; + FxExpression *data = new FxExpression; data->Type = EX_Const; data->Value.Type = VAL_Int; data->Value.Int = static_cast(sym)->Value; @@ -719,9 +493,11 @@ static ExpData *ParseExpressionA (FScanner &sc, const PClass *cls) return NULL; } } + */ else if (sc.CheckToken(TK_Identifier)) { - switch (FName(sc.String)) + FName identifier = FName(sc.String); + switch (identifier) { case NAME_Random: { @@ -739,15 +515,12 @@ static ExpData *ParseExpressionA (FScanner &sc, const PClass *cls) } sc.MustGetToken('('); - ExpData *data = new ExpData; - data->Type = EX_Random; - data->RNG = rng; - - data->Children[0] = ParseExpressionM (sc, cls); + FxExpression *min = ParseExpressionM (sc, cls); sc.MustGetToken(','); - data->Children[1] = ParseExpressionM (sc, cls); + FxExpression *max = ParseExpressionM (sc, cls); sc.MustGetToken(')'); - return data; + + return new FxRandom(rng, min, max, sc); } break; @@ -768,25 +541,32 @@ static ExpData *ParseExpressionA (FScanner &sc, const PClass *cls) sc.MustGetToken('('); - ExpData *data = new ExpData; - data->Type = EX_Random2; - data->RNG = rng; + FxExpression *mask = NULL; if (!sc.CheckToken(')')) { - data->Children[0] = ParseExpressionM(sc, cls); + mask = ParseExpressionM(sc, cls); sc.MustGetToken(')'); } - return data; + return new FxRandom2(rng, mask, sc); } break; + case NAME_Abs: + { + sc.MustGetToken('('); + FxExpression *x = ParseExpressionM (sc, cls); + sc.MustGetToken(')'); + return new FxAbs(x); + } + case NAME_Sin: { sc.MustGetToken('('); - ExpData *data = new ExpData; + FxExpression *data = new FxExpression; data->Type = EX_Sin; + data->ValueType = VAL_Float; data->Children[0] = ParseExpressionM (sc, cls); @@ -799,8 +579,9 @@ static ExpData *ParseExpressionA (FScanner &sc, const PClass *cls) { sc.MustGetToken('('); - ExpData *data = new ExpData; + FxExpression *data = new FxExpression; data->Type = EX_Cos; + data->ValueType = VAL_Float; data->Children[0] = ParseExpressionM (sc, cls); @@ -821,16 +602,17 @@ static ExpData *ParseExpressionA (FScanner &sc, const PClass *cls) sc.MustGetToken('('); - ExpData *data = new ExpData, **left; + 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) { - ExpData *right = new ExpData; + FxExpression *right = new FxExpression; right->Type = EX_Right; right->Children[0] = ParseExpressionM (sc, cls); *left = right; @@ -849,14 +631,11 @@ static ExpData *ParseExpressionA (FScanner &sc, const PClass *cls) // Check if this is a constant if (cls != NULL) { - PSymbol *sym = cls->Symbols.FindSymbol (sc.String, true); + PSymbol *sym = cls->Symbols.FindSymbol (identifier, true); + if (sym == NULL) sym = GlobalSymbols.FindSymbol (identifier, true); if (sym != NULL && sym->SymbolType == SYM_Const) { - ExpData *data = new ExpData; - data->Type = EX_Const; - data->Value.Type = VAL_Int; - data->Value.Int = static_cast(sym)->Value; - return data; + return new FxConstant(static_cast(sym)->Value, sc); } } @@ -875,10 +654,11 @@ static ExpData *ParseExpressionA (FScanner &sc, const PClass *cls) if (varid == -1) sc.ScriptError ("Unknown value '%s'", sc.String); - ExpData *data = new ExpData; + FxExpression *data = new FxExpression; data->Type = EX_Var; data->Value.Type = VAL_Int; data->Value.Int = varid; + data->ValueType = ExpVars[varid].ValueType; if (ExpVars[varid].array) { @@ -908,7 +688,7 @@ bool IsExpressionConst(int id) { if (StateExpressions.Size() <= (unsigned int)id) return false; - return StateExpressions[id]->Type == EX_Const; + return StateExpressions[id]->isConstant(); } int EvalExpressionI (int id, AActor *self, const PClass *cls) @@ -920,7 +700,7 @@ int EvalExpressionI (int id, AActor *self, const PClass *cls) cls = self->GetClass(); } - ExpVal val = EvalExpression (StateExpressions[id], self, cls); + ExpVal val = StateExpressions[id]->EvalExpression (self, cls); switch (val.Type) { @@ -932,7 +712,7 @@ int EvalExpressionI (int id, AActor *self, const PClass *cls) } } -float EvalExpressionF (int id, AActor *self, const PClass *cls) +double EvalExpressionF (int id, AActor *self, const PClass *cls) { if (StateExpressions.Size() <= (unsigned int)id) return 0.f; @@ -941,13 +721,13 @@ float EvalExpressionF (int id, AActor *self, const PClass *cls) cls = self->GetClass(); } - ExpVal val = EvalExpression (StateExpressions[id], self, cls); + ExpVal val = StateExpressions[id]->EvalExpression (self, cls); switch (val.Type) { default: case VAL_Int: - return (float)val.Int; + return (double)val.Int; case VAL_Float: return val.Float; } @@ -962,7 +742,7 @@ fixed_t EvalExpressionFix (int id, AActor *self, const PClass *cls) cls = self->GetClass(); } - ExpVal val = EvalExpression (StateExpressions[id], self, cls); + ExpVal val = StateExpressions[id]->EvalExpression (self, cls); switch (val.Type) { @@ -974,20 +754,17 @@ fixed_t EvalExpressionFix (int id, AActor *self, const PClass *cls) } } -static ExpVal EvalExpression (ExpData *data, AActor *self, const PClass *cls) +ExpVal FxExpression::EvalExpression (AActor *self, const PClass *cls) { ExpVal val; val.Type = VAL_Int; // Placate GCC - switch (data->Type) + switch (Type) { case EX_NOP: - assert (data->Type != EX_NOP); - val = data->Value; - break; - case EX_Const: - val = data->Value; + assert (Type != EX_NOP); + val = Value; break; case EX_Var: if (!self) @@ -997,539 +774,18 @@ static ExpVal EvalExpression (ExpData *data, AActor *self, const PClass *cls) else { int id = 0; - if (ExpVars[data->Value.Int].array) + if (ExpVars[Value.Int].array) { - ExpVal idval = EvalExpression (data->Children[0], self, cls); - id = ((idval.Type == VAL_Int) ? idval.Int : (int)idval.Float) % ExpVars[data->Value.Int].array; + ExpVal idval = Children[0]->EvalExpression (self, cls); + id = ((idval.Type == VAL_Int) ? idval.Int : (int)idval.Float) % ExpVars[Value.Int].array; } - val = ExpVars[data->Value.Int].get (self, id); + val = ExpVars[Value.Int].get (self, id); } break; - case EX_Compl: - { - ExpVal a = EvalExpression (data->Children[0], self, cls); - - val.Type = VAL_Int; - val.Int = ~((a.Type == VAL_Int) ? a.Int : (int)a.Float); - } - break; - case EX_Not: - { - ExpVal a = EvalExpression (data->Children[0], self, cls); - - val.Type = VAL_Int; - val.Int = !((a.Type == VAL_Int) ? a.Int : (int)a.Float); - } - break; - case EX_Minus: - { - val = EvalExpression (data->Children[0], self, cls); - - if (val.Type == VAL_Int) - val.Int = -val.Int; - else - val.Float = -val.Float; - } - break; - case EX_Mul: - { - ExpVal a = EvalExpression (data->Children[0], self, cls); - ExpVal b = EvalExpression (data->Children[1], self, cls); - - if (a.Type == VAL_Int) - { - if (b.Type == VAL_Int) - { - val.Type = VAL_Int; - val.Int = a.Int * b.Int; - } - else - { - val.Type = VAL_Float; - val.Float = a.Int * b.Float; - } - } - else - { - val.Type = VAL_Float; - if (b.Type == VAL_Int) - val.Float = a.Float * b.Int; - else - val.Float = a.Float * b.Float; - } - } - break; - case EX_Div: - { - ExpVal a = EvalExpression (data->Children[0], self, cls); - ExpVal b = EvalExpression (data->Children[1], self, cls); - - if (b.Int == 0) - { - I_FatalError ("Division by zero"); - } - - if (a.Type == VAL_Int) - { - if (b.Type == VAL_Int) - { - val.Type = VAL_Int; - val.Int = a.Int / b.Int; - } - else - { - val.Type = VAL_Float; - val.Float = a.Int / b.Float; - } - } - else - { - val.Type = VAL_Float; - if (b.Type == VAL_Int) - val.Float = a.Float / b.Int; - else - val.Float = a.Float / b.Float; - } - } - break; - case EX_Mod: - { - ExpVal a = EvalExpression (data->Children[0], self, cls); - ExpVal b = EvalExpression (data->Children[1], self, cls); - - if (b.Int == 0) - { - I_FatalError ("Division by zero"); - } - - if (a.Type == VAL_Int) - { - if (b.Type == VAL_Int) - { - val.Type = VAL_Int; - val.Int = a.Int % b.Int; - } - else - { - val.Type = VAL_Float; - val.Float = fmodf (a.Int, b.Float); - } - } - else - { - val.Type = VAL_Float; - if (b.Type == VAL_Int) - val.Float = fmodf (a.Float, b.Int); - else - val.Float = fmodf (a.Float, b.Float); - } - } - break; - case EX_Add: - { - ExpVal a = EvalExpression (data->Children[0], self, cls); - ExpVal b = EvalExpression (data->Children[1], self, cls); - - if (a.Type == VAL_Int) - { - if (b.Type == VAL_Int) - { - val.Type = VAL_Int; - val.Int = a.Int + b.Int; - } - else - { - val.Type = VAL_Float; - val.Float = a.Int + b.Float; - } - } - else - { - val.Type = VAL_Float; - if (b.Type == VAL_Int) - val.Float = a.Float + b.Int; - else - val.Float = a.Float + b.Float; - } - } - break; - case EX_Sub: - { - ExpVal a = EvalExpression (data->Children[0], self, cls); - ExpVal b = EvalExpression (data->Children[1], self, cls); - - if (a.Type == VAL_Int) - { - if (b.Type == VAL_Int) - { - val.Type = VAL_Int; - val.Int = a.Int - b.Int; - } - else - { - val.Type = VAL_Float; - val.Float = a.Int - b.Float; - } - } - else - { - val.Type = VAL_Float; - if (b.Type == VAL_Int) - val.Float = a.Float - b.Int; - else - val.Float = a.Float - b.Float; - } - } - break; - case EX_LShift: - { - ExpVal a = EvalExpression (data->Children[0], self, cls); - ExpVal b = EvalExpression (data->Children[1], self, cls); - - val.Type = VAL_Int; - - if (a.Type == VAL_Int) - { - if (b.Type == VAL_Int) - val.Int = a.Int << b.Int; - else - val.Int = a.Int << (int)b.Float; - } - else - { - if (b.Type == VAL_Int) - val.Int = (int)a.Float << b.Int; - else - val.Int = (int)a.Float << (int)b.Float; - } - } - break; - case EX_RShift: - { - ExpVal a = EvalExpression (data->Children[0], self, cls); - ExpVal b = EvalExpression (data->Children[1], self, cls); - - val.Type = VAL_Int; - - if (a.Type == VAL_Int) - { - if (b.Type == VAL_Int) - val.Int = a.Int >> b.Int; - else - val.Int = a.Int >> (int)b.Float; - } - else - { - if (b.Type == VAL_Int) - val.Int = (int)a.Float >> b.Int; - else - val.Int = (int)a.Float >> (int)b.Float; - } - } - break; - case EX_LT: - { - ExpVal a = EvalExpression (data->Children[0], self, cls); - ExpVal b = EvalExpression (data->Children[1], self, cls); - - val.Type = VAL_Int; - - if (a.Type == VAL_Int) - { - if (b.Type == VAL_Int) - val.Int = a.Int < b.Int; - else - val.Int = a.Int < b.Float; - } - else - { - if (b.Type == VAL_Int) - val.Int = a.Float < b.Int; - else - val.Int = a.Float < b.Float; - } - } - break; - case EX_GT: - { - ExpVal a = EvalExpression (data->Children[0], self, cls); - ExpVal b = EvalExpression (data->Children[1], self, cls); - - val.Type = VAL_Int; - - if (a.Type == VAL_Int) - { - if (b.Type == VAL_Int) - val.Int = a.Int > b.Int; - else - val.Int = a.Int > b.Float; - } - else - { - if (b.Type == VAL_Int) - val.Int = a.Float > b.Int; - else - val.Int = a.Float > b.Float; - } - } - break; - case EX_LE: - { - ExpVal a = EvalExpression (data->Children[0], self, cls); - ExpVal b = EvalExpression (data->Children[1], self, cls); - - val.Type = VAL_Int; - - if (a.Type == VAL_Int) - { - if (b.Type == VAL_Int) - val.Int = a.Int <= b.Int; - else - val.Int = a.Int <= b.Float; - } - else - { - if (b.Type == VAL_Int) - val.Int = a.Float <= b.Int; - else - val.Int = a.Float <= b.Float; - } - } - break; - case EX_GE: - { - ExpVal a = EvalExpression (data->Children[0], self, cls); - ExpVal b = EvalExpression (data->Children[1], self, cls); - - val.Type = VAL_Int; - - if (a.Type == VAL_Int) - { - if (b.Type == VAL_Int) - val.Int = a.Int >= b.Int; - else - val.Int = a.Int >= b.Float; - } - else - { - if (b.Type == VAL_Int) - val.Int = a.Float >= b.Int; - else - val.Int = a.Float >= b.Float; - } - } - break; - case EX_Eq: - { - ExpVal a = EvalExpression (data->Children[0], self, cls); - ExpVal b = EvalExpression (data->Children[1], self, cls); - - val.Type = VAL_Int; - - if (a.Type == VAL_Int) - { - if (b.Type == VAL_Int) - val.Int = a.Int == b.Int; - else - val.Int = a.Int == b.Float; - } - else - { - if (b.Type == VAL_Int) - val.Int = a.Float == b.Int; - else - val.Int = a.Float == b.Float; - } - } - break; - case EX_NE: - { - ExpVal a = EvalExpression (data->Children[0], self, cls); - ExpVal b = EvalExpression (data->Children[1], self, cls); - - val.Type = VAL_Int; - - if (a.Type == VAL_Int) - { - if (b.Type == VAL_Int) - val.Int = a.Int != b.Int; - else - val.Int = a.Int != b.Float; - } - else - { - if (b.Type == VAL_Int) - val.Int = a.Float != b.Int; - else - val.Int = a.Float != b.Float; - } - } - break; - case EX_And: - { - ExpVal a = EvalExpression (data->Children[0], self, cls); - ExpVal b = EvalExpression (data->Children[1], self, cls); - - val.Type = VAL_Int; - - if (a.Type == VAL_Int) - { - if (b.Type == VAL_Int) - val.Int = a.Int & b.Int; - else - val.Int = a.Int & (int)b.Float; - } - else - { - if (b.Type == VAL_Int) - val.Int = (int)a.Float & b.Int; - else - val.Int = (int)a.Float & (int)b.Float; - } - } - break; - case EX_Xor: - { - ExpVal a = EvalExpression (data->Children[0], self, cls); - ExpVal b = EvalExpression (data->Children[1], self, cls); - - val.Type = VAL_Int; - - if (a.Type == VAL_Int) - { - if (b.Type == VAL_Int) - val.Int = a.Int ^ b.Int; - else - val.Int = a.Int ^ (int)b.Float; - } - else - { - if (b.Type == VAL_Int) - val.Int = (int)a.Float ^ b.Int; - else - val.Int = (int)a.Float ^ (int)b.Float; - } - } - break; - case EX_Or: - { - ExpVal a = EvalExpression (data->Children[0], self, cls); - ExpVal b = EvalExpression (data->Children[1], self, cls); - - val.Type = VAL_Int; - - if (a.Type == VAL_Int) - { - if (b.Type == VAL_Int) - val.Int = a.Int | b.Int; - else - val.Int = a.Int | (int)b.Float; - } - else - { - if (b.Type == VAL_Int) - val.Int = (int)a.Float | b.Int; - else - val.Int = (int)a.Float | (int)b.Float; - } - } - break; - case EX_LogAnd: - { - ExpVal a = EvalExpression (data->Children[0], self, cls); - ExpVal b = EvalExpression (data->Children[1], self, cls); - - val.Type = VAL_Int; - - if (a.Type == VAL_Int) - { - if (b.Type == VAL_Int) - val.Int = a.Int && b.Int; - else - val.Int = a.Int && b.Float; - } - else - { - if (b.Type == VAL_Int) - val.Int = a.Float && b.Int; - else - val.Int = a.Float && b.Float; - } - } - break; - case EX_LogOr: - { - ExpVal a = EvalExpression (data->Children[0], self, cls); - ExpVal b = EvalExpression (data->Children[1], self, cls); - - val.Type = VAL_Int; - - if (a.Type == VAL_Int) - { - if (b.Type == VAL_Int) - val.Int = a.Int || b.Int; - else - val.Int = a.Int || b.Float; - } - else - { - if (b.Type == VAL_Int) - val.Int = a.Float || b.Int; - else - val.Int = a.Float || b.Float; - } - } - break; - case EX_Cond: - { - ExpVal a = EvalExpression (data->Children[0], self, cls); - - if (a.Type == VAL_Float) - a.Int = (int)a.Float; - - val = EvalExpression (data->Children[1]->Children[!!a.Int], self, cls); - } - break; - - case EX_Random: - { - ExpVal a = EvalExpression (data->Children[0], self, cls); - ExpVal b = EvalExpression (data->Children[1], self, cls); - - int min = (a.Type == VAL_Int) ? a.Int : (int)a.Float; - int max = (b.Type == VAL_Int) ? b.Int : (int)b.Float; - - val.Type = VAL_Int; - - if (max < min) - { - swap (max, min); - } - - val.Int = (*data->RNG)(max - min + 1) + min; - } - break; - - case EX_Random2: - { - if (data->Children[0] == NULL) - { - val.Type = VAL_Int; - val.Int = data->RNG->Random2(); - } - else - { - ExpVal a = EvalExpression (data->Children[0], self, cls); - val.Type = VAL_Int; - val.Int = data->RNG->Random2((a.Type == VAL_Int) ? a.Int : (int)a.Float); - } - } - break; - case EX_Sin: { - ExpVal a = EvalExpression (data->Children[0], self, cls); + ExpVal a = Children[0]->EvalExpression (self, cls); angle_t angle = (a.Type == VAL_Int) ? (a.Int * ANGLE_1) : angle_t(a.Float * ANGLE_1); val.Type = VAL_Float; @@ -1539,7 +795,7 @@ static ExpVal EvalExpression (ExpData *data, AActor *self, const PClass *cls) case EX_Cos: { - ExpVal a = EvalExpression (data->Children[0], self, cls); + ExpVal a = Children[0]->EvalExpression (self, cls); angle_t angle = (a.Type == VAL_Int) ? (a.Int * ANGLE_1) : angle_t(a.Float * ANGLE_1); val.Type = VAL_Float; @@ -1551,11 +807,11 @@ static ExpVal EvalExpression (ExpData *data, AActor *self, const PClass *cls) { int parms[5] = { 0, 0, 0, 0 }; int i = 0; - ExpData *parm = data; + FxExpression *parm = this; while (parm != NULL && i < 5) { - ExpVal val = EvalExpression (parm->Children[0], self, cls); + ExpVal val = parm->Children[0]->EvalExpression (self, cls); if (val.Type == VAL_Int) { parms[i] = val.Int; @@ -1569,14 +825,14 @@ static ExpVal EvalExpression (ExpData *data, AActor *self, const PClass *cls) } val.Type = VAL_Int; - val.Int = LineSpecials[data->Value.Int] (NULL, self, false, + 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 (data->Type != EX_Right); + assert (Type != EX_Right); break; } @@ -1584,32 +840,66 @@ static ExpVal EvalExpression (ExpData *data, AActor *self, const PClass *cls) } -// -// InitExpressions -// [GRB] Set up expression data -// - -void InitExpressions () +bool FxExpression::isConstant() const { - // StateExpressions[0] always is const 0; - ExpData *data = new ExpData; - data->Type = EX_Const; - data->Value.Type = VAL_Int; - data->Value.Int = 0; + return false; +} - StateExpressions.Push (data); +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; } -// -// ClearExpressions -// [GRB] Free all expression data -// -void ClearExpressions () +/* +some stuff for later +static FxExpression *ParseExpressionA (FScanner &sc, const PClass *cls) { - ExpData *data; + else if (sc.CheckToken(TK_Identifier)) + { + FName IdName = FName(sc.String); + switch (IdName) + { + default: + { + FScriptPosition scriptpos(sc); + if (sc.CheckToken('(')) + { + // function call + TArray arguments; - while (StateExpressions.Pop (data)) - delete data; + do + { + FxExpression *data = ParseExpressionM(sc, cls); + arguments.Push(data); + } + while (sc.CheckToken(',')); + return new FxFunctionCall(arguments, scriptpos); + } + else + { + FxExpression *data = new FxIdentifier(IdName, scriptpos); + if (sc.CheckToken('[')) + { + FxExpression *index = ParseExpressionM(sc, cls); + sc.MustGetToken(']'); + data = new FxArrayElement(data, index); + } + return data; + } + } + break; + } + } + else + { + FString tokname = sc.TokenName(sc.TokenType, sc.String); + sc.ScriptError ("Unexpected token %s", tokname.GetChars()); + return NULL; + } } + +*/ \ No newline at end of file diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h new file mode 100644 index 0000000000..292cde6706 --- /dev/null +++ b/src/thingdef/thingdef_exp.h @@ -0,0 +1,584 @@ +#ifndef THINGDEF_EXP_H +#define THINGDEF_EXP_H + +/* +** thingdef_exp.h +** +** Expression evaluation +** +**--------------------------------------------------------------------------- +** Copyright 2008 Christoph Oelckers +** 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. +** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be +** covered by the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or (at +** your option) any later version. +** +** 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 "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 FxType +{ + EBaseType type; +public: + FxType(EBaseType t) { type = t; } + FxType(const FxType & t) { type = t.type; } + FxType &operator =(const FxType &t) { type = t.type; return *this; } + + EBaseType GetBaseType() const { return type; } +}; +*/ + +//========================================================================== +// +// +// +//========================================================================== + +enum +{ + MSG_WARNING, + MSG_ERROR, + MSG_DEBUG, + MSG_LOG, + MSG_DEBUGLOG +}; + +//========================================================================== +// +// +// +//========================================================================== + +struct FScriptPosition +{ + FString FileName; + int ScriptLine; + + FScriptPosition() + { + ScriptLine=0; + } + FScriptPosition(const FScriptPosition &other) + { + FileName = other.FileName; + ScriptLine = other.ScriptLine; + } + FScriptPosition(FString fname, int line) + { + FileName = fname; + ScriptLine = line; + } + FScriptPosition(FScanner &sc) + { + FileName = sc.ScriptName; + ScriptLine = sc.GetMessageLine(); + } + FScriptPosition &operator=(const FScriptPosition &other) + { + FileName = other.FileName; + ScriptLine = other.ScriptLine; + return *this; + } + + void Message(int severity, const char *message,...); +}; + +//========================================================================== +// +// +// +//========================================================================== + +struct FCompileContext +{ + const PClass *cls; +}; + +//========================================================================== +// +// +// +//========================================================================== + +enum ExpOp +{ + EX_NOP, + + EX_Var, + + EX_Sin, // sin (angle) + EX_Cos, // cos (angle) + EX_ActionSpecial, + EX_Right, +}; + +//========================================================================== +// +// +// +//========================================================================== + +enum ExpValType +{ + VAL_Int, + VAL_Float, + VAL_Unknown, + + // only used for accessing class member fields to ensure proper conversion + VAL_Fixed, + VAL_Angle, +}; + +//========================================================================== +// +// +// +//========================================================================== + +struct ExpVal +{ + ExpValType Type; + union + { + int Int; + double Float; + }; + + int GetInt() + { + return Type == VAL_Int? Int : Type == VAL_Float? int(Float) : 0; + } + + double GetFloat() + { + return Type == VAL_Int? double(Int) : Type == VAL_Float? Float : 0; + } + + bool GetBool() + { + return Type == VAL_Int? !!Int : Type == VAL_Float? Float!=0. : false; + } + +}; + + +//========================================================================== +// +// +// +//========================================================================== + +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); + FxExpression *ResolveAsBoolean(FCompileContext &ctx) + { + // This will need more handling if other types than Int and Float are added + return Resolve(ctx); + } + + virtual ExpVal EvalExpression (AActor *self, const PClass *cls); + virtual bool isConstant() const; + + int Type; + ExpVal Value; + FxExpression *Children[2]; + + FScriptPosition ScriptPosition; + int ValueType; +protected: + bool isresolved; +}; + +//========================================================================== +// +// ZxConstant +// +//========================================================================== + +class FxConstant : public FxExpression +{ + ExpVal value; + +public: + FxConstant(int val, const FScriptPosition &pos) : FxExpression(pos) + { + ValueType = value.Type = VAL_Int; + value.Int = val; + } + + FxConstant(double val, const FScriptPosition &pos) : FxExpression(pos) + { + ValueType = value.Type = VAL_Float; + value.Float = val; + } + + FxConstant(ExpVal cv, const FScriptPosition &pos) : FxExpression(pos) + { + value = cv; + ValueType = cv.Type; + } + + bool isConstant() const + { + return true; + } + ExpVal EvalExpression (AActor *self, const PClass *cls); +}; + + +//========================================================================== +// +// +// +//========================================================================== + +class FxIntCast : public FxExpression +{ + FxExpression *basex; + +public: + + FxIntCast(FxExpression *x); + ~FxIntCast(); + FxExpression *Resolve(FCompileContext&); + + ExpVal EvalExpression (AActor *self, const PClass *cls); +}; + + +//========================================================================== +// +// FxSign +// +//========================================================================== + +class FxPlusSign : public FxExpression +{ + FxExpression *Operand; + +public: + FxPlusSign(FxExpression*); + ~FxPlusSign(); + FxExpression *Resolve(FCompileContext&); +}; + +//========================================================================== +// +// FxSign +// +//========================================================================== + +class FxMinusSign : public FxExpression +{ + FxExpression *Operand; + +public: + FxMinusSign(FxExpression*); + ~FxMinusSign(); + FxExpression *Resolve(FCompileContext&); + ExpVal EvalExpression (AActor *self, const PClass *cls); +}; + +//========================================================================== +// +// FxUnaryNot +// +//========================================================================== + +class FxUnaryNotBitwise : public FxExpression +{ + FxExpression *Operand; + +public: + FxUnaryNotBitwise(FxExpression*); + ~FxUnaryNotBitwise(); + FxExpression *Resolve(FCompileContext&); + ExpVal EvalExpression (AActor *self, const PClass *cls); +}; + +//========================================================================== +// +// FxUnaryNot +// +//========================================================================== + +class FxUnaryNotBoolean : public FxExpression +{ + FxExpression *Operand; + +public: + FxUnaryNotBoolean(FxExpression*); + ~FxUnaryNotBoolean(); + FxExpression *Resolve(FCompileContext&); + ExpVal EvalExpression (AActor *self, const PClass *cls); +}; + +//========================================================================== +// +// FxBinary +// +//========================================================================== + +class FxBinary : public FxExpression +{ +public: + int Operator; + FxExpression *left; + FxExpression *right; + + FxBinary(int, FxExpression*, FxExpression*); + ~FxBinary(); + bool ResolveLR(FCompileContext& ctx, bool castnumeric); +}; + +//========================================================================== +// +// FxBinary +// +//========================================================================== + +class FxAddSub : public FxBinary +{ +public: + + FxAddSub(int, FxExpression*, FxExpression*); + FxExpression *Resolve(FCompileContext&); + ExpVal EvalExpression (AActor *self, const PClass *cls); +}; + +//========================================================================== +// +// FxBinary +// +//========================================================================== + +class FxMulDiv : public FxBinary +{ +public: + + FxMulDiv(int, FxExpression*, FxExpression*); + FxExpression *Resolve(FCompileContext&); + ExpVal EvalExpression (AActor *self, const PClass *cls); +}; + +//========================================================================== +// +// FxBinary +// +//========================================================================== + +class FxCompareRel : public FxBinary +{ +public: + + FxCompareRel(int, FxExpression*, FxExpression*); + FxExpression *Resolve(FCompileContext&); + ExpVal EvalExpression (AActor *self, const PClass *cls); +}; + +//========================================================================== +// +// FxBinary +// +//========================================================================== + +class FxCompareEq : public FxBinary +{ +public: + + FxCompareEq(int, FxExpression*, FxExpression*); + FxExpression *Resolve(FCompileContext&); + ExpVal EvalExpression (AActor *self, const PClass *cls); +}; + +//========================================================================== +// +// FxBinary +// +//========================================================================== + +class FxBinaryInt : public FxBinary +{ +public: + + FxBinaryInt(int, FxExpression*, FxExpression*); + FxExpression *Resolve(FCompileContext&); + ExpVal EvalExpression (AActor *self, const PClass *cls); +}; + +//========================================================================== +// +// FxBinaryLogical +// +//========================================================================== + +class FxBinaryLogical : public FxExpression +{ +public: + int Operator; + FxExpression *left; + FxExpression *right; + + FxBinaryLogical(int, FxExpression*, FxExpression*); + ~FxBinaryLogical(); + FxExpression *Resolve(FCompileContext&); + + ExpVal EvalExpression (AActor *self, const PClass *cls); +}; + +//========================================================================== +// +// FxConditional +// +//========================================================================== + +class FxConditional : public FxExpression +{ +public: + FxExpression *condition; + FxExpression *truex; + FxExpression *falsex; + + FxConditional(FxExpression*, FxExpression*, FxExpression*); + ~FxConditional(); + FxExpression *Resolve(FCompileContext&); + + ExpVal EvalExpression (AActor *self, const PClass *cls); +}; + +//========================================================================== +// +// +// +//========================================================================== + +class FxAbs : public FxExpression +{ + FxExpression *val; + +public: + + FxAbs(FxExpression *v); + ~FxAbs(); + FxExpression *Resolve(FCompileContext&); + + ExpVal EvalExpression (AActor *self, const PClass *cls); +}; + +//========================================================================== +// +// +// +//========================================================================== + +class FxRandom : public FxExpression +{ + FRandom * rng; + FxExpression *min, *max; + +public: + + FxRandom(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos); + ~FxRandom(); + FxExpression *Resolve(FCompileContext&); + + ExpVal EvalExpression (AActor *self, const PClass *cls); +}; + + + +//========================================================================== +// +// +// +//========================================================================== + +class FxRandom2 : public FxExpression +{ + FRandom * rng; + FxExpression *mask; + +public: + + FxRandom2(FRandom *, FxExpression *m, const FScriptPosition &pos); + ~FxRandom2(); + FxExpression *Resolve(FCompileContext&); + + ExpVal EvalExpression (AActor *self, const PClass *cls); +}; + + +FxExpression *ParseExpression (FScanner &sc, PClass *cls); + + +#endif \ No newline at end of file diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp new file mode 100644 index 0000000000..b5b9663cf1 --- /dev/null +++ b/src/thingdef/thingdef_expression.cpp @@ -0,0 +1,1377 @@ +/* +** thingdef_expression.cpp +** +** Expression evaluation +** +**--------------------------------------------------------------------------- +** Copyright 2008 Christoph Oelckers +** 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. +** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be +** covered by the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or (at +** your option) any later version. +** +** 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 "actor.h" +#include "sc_man.h" +#include "tarray.h" +#include "templates.h" +#include "cmdlib.h" +#include "i_system.h" +#include "m_random.h" +#include "a_pickups.h" +#include "thingdef.h" +#include "p_lnspec.h" +#include "doomstat.h" +#include "thingdef_exp.h" + + +//========================================================================== +// +// FScriptPosition::Message +// +//========================================================================== + +void STACK_ARGS FScriptPosition::Message (int severity, const char *message, ...) +{ + FString composed; + + if (message == NULL) + { + composed = "Bad syntax."; + } + else + { + va_list arglist; + va_start (arglist, message); + composed.VFormat (message, arglist); + va_end (arglist); + } + const char *type = ""; + int level = PRINT_HIGH; + + switch (severity) + { + default: + return; + + case MSG_WARNING: + type = "warning"; + break; + + case MSG_ERROR: + type = "error"; + break; + + case MSG_DEBUG: + if (!developer) return; + type = "message"; + break; + + case MSG_LOG: + type = "message"; + level = PRINT_LOG; + break; + + case MSG_DEBUGLOG: + if (!developer) return; + type = "message"; + level = PRINT_LOG; + break; + } + + Printf (level, "Script %s, \"%s\" line %d:\n%s\n", type, + FileName.GetChars(), ScriptLine, composed.GetChars()); +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpVal FxConstant::EvalExpression (AActor *self, const PClass *cls) +{ + return value; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxIntCast::FxIntCast(FxExpression *x) +: FxExpression(x->ScriptPosition) +{ + basex=x; + ValueType = VAL_Int; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxIntCast::~FxIntCast() +{ + SAFE_DELETE(basex); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxIntCast::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(basex, ctx); + + if (basex->isConstant()) + { + ExpVal constval = basex->EvalExpression(NULL, ctx.cls); + FxExpression *x = new FxConstant(constval.GetInt(), ScriptPosition); + delete this; + return x; + } + else if (basex->ValueType == VAL_Int) + { + FxExpression *x = basex; + basex = NULL; + delete this; + return x; + } + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpVal FxIntCast::EvalExpression (AActor *self, const PClass *cls) +{ + ExpVal baseval = basex->EvalExpression(self, cls); + baseval.Int = baseval.GetInt(); + baseval.Type = VAL_Int; + return baseval; +} + + +//========================================================================== +// +// +// +//========================================================================== + +FxPlusSign::FxPlusSign(FxExpression *operand) +: FxExpression(operand->ScriptPosition) +{ + Operand=operand; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxPlusSign::~FxPlusSign() +{ + SAFE_DELETE(Operand); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxPlusSign::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Operand, ctx); + + FxExpression *e = Operand; + Operand = NULL; + delete this; + return e; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxMinusSign::FxMinusSign(FxExpression *operand) +: FxExpression(operand->ScriptPosition) +{ + Operand=operand; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxMinusSign::~FxMinusSign() +{ + SAFE_DELETE(Operand); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxMinusSign::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Operand, ctx); + + if (Operand->isConstant()) + { + ExpVal val = Operand->EvalExpression(NULL, ctx.cls); + FxExpression *e = val.Type == VAL_Int? + new FxConstant(-val.Int, ScriptPosition) : + new FxConstant(-val.Float, ScriptPosition); + delete this; + return e; + } + ValueType = Operand->ValueType; + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpVal FxMinusSign::EvalExpression (AActor *self, const PClass *cls) +{ + ExpVal ret; + + if (ValueType == VAL_Int) + { + ret.Int = -Operand->EvalExpression(self, cls).GetInt(); + ret.Type = VAL_Int; + } + else + { + ret.Float = -Operand->EvalExpression(self, cls).GetFloat(); + ret.Type = VAL_Float; + } + return ret; +} + + +//========================================================================== +// +// +// +//========================================================================== + +FxUnaryNotBitwise::FxUnaryNotBitwise(FxExpression *operand) +: FxExpression(operand->ScriptPosition) +{ + Operand=operand; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxUnaryNotBitwise::~FxUnaryNotBitwise() +{ + SAFE_DELETE(Operand); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Operand, ctx); + + /* DECORATE allows this. + if (Operand->ValueType != VAL_Int) + { + ScriptPosition.Message(MSG_ERROR, "Integer type expected"); + delete this; + return NULL; + } + */ + + if (Operand->isConstant()) + { + int result = ~Operand->EvalExpression(NULL, ctx.cls).GetInt(); + FxExpression *e = new FxConstant(result, ScriptPosition); + delete this; + return e; + } + ValueType = VAL_Int; + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpVal FxUnaryNotBitwise::EvalExpression (AActor *self, const PClass *cls) +{ + ExpVal ret; + + ret.Int = ~Operand->EvalExpression(self, cls).GetInt(); + ret.Type = VAL_Int; + return ret; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxUnaryNotBoolean::FxUnaryNotBoolean(FxExpression *operand) +: FxExpression(operand->ScriptPosition) +{ + Operand=operand; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxUnaryNotBoolean::~FxUnaryNotBoolean() +{ + SAFE_DELETE(Operand); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + if (Operand) + { + Operand = Operand->ResolveAsBoolean(ctx); + } + if (!Operand) + { + delete this; + return NULL; + } + + if (Operand->isConstant()) + { + bool result = !Operand->EvalExpression(NULL, ctx.cls).GetBool(); + FxExpression *e = new FxConstant(result, ScriptPosition); + delete this; + return e; + } + ValueType = VAL_Int; + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpVal FxUnaryNotBoolean::EvalExpression (AActor *self, const PClass *cls) +{ + ExpVal ret; + + ret.Int = !Operand->EvalExpression(self, cls).GetBool(); + ret.Type = VAL_Int; + return ret; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxBinary::FxBinary(int o, FxExpression *l, FxExpression *r) +: FxExpression(l->ScriptPosition) +{ + Operator=o; + left=l; + right=r; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxBinary::~FxBinary() +{ + SAFE_DELETE(left); + SAFE_DELETE(right); +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FxBinary::ResolveLR(FCompileContext& ctx, bool castnumeric) +{ + RESOLVE(left, ctx); + RESOLVE(right, ctx); + if (!left || !right) + { + delete this; + return false; + } + + ValueType = left->ValueType; + if (castnumeric && right->ValueType == VAL_Float) + { + ValueType = VAL_Float; + } + /* not for DECORATE - will be activated later + else if (left->ValueType != right->ValueType) + { + ScriptPosition.Message(MSG_ERROR, "Type mismatch in expression"); + delete this; + return false; + } + */ + return true; +} + + +//========================================================================== +// +// +// +//========================================================================== + +FxAddSub::FxAddSub(int o, FxExpression *l, FxExpression *r) +: FxBinary(o, l, r) +{ +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxAddSub::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + if (!ResolveLR(ctx, true)) return NULL; + + if (left->isConstant() && right->isConstant()) + { + if (ValueType == VAL_Float) + { + double v; + double v1 = left->EvalExpression(NULL, ctx.cls).GetFloat(); + double v2 = right->EvalExpression(NULL, ctx.cls).GetFloat(); + + v = Operator == '+'? v1 + v2 : + Operator == '-'? v1 - v2 : 0; + + FxExpression *e = new FxConstant(v, ScriptPosition); + delete this; + return e; + } + else + { + int v; + int v1 = left->EvalExpression(NULL, ctx.cls).GetInt(); + int v2 = right->EvalExpression(NULL, ctx.cls).GetInt(); + + v = Operator == '+'? v1 + v2 : + Operator == '-'? v1 - v2 : 0; + + FxExpression *e = new FxConstant(v, ScriptPosition); + delete this; + return e; + + } + } + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpVal FxAddSub::EvalExpression (AActor *self, const PClass *cls) +{ + ExpVal ret; + + if (left->ValueType == VAL_Float || right->ValueType ==VAL_Float) + { + double v1 = left->EvalExpression(self, cls).GetFloat(); + double v2 = right->EvalExpression(self, cls).GetFloat(); + + ret.Type = VAL_Float; + ret.Float = Operator == '+'? v1 + v2 : + Operator == '-'? v1 - v2 : 0; + } + else + { + int v1 = left->EvalExpression(self, cls).GetInt(); + int v2 = right->EvalExpression(self, cls).GetInt(); + + ret.Type = VAL_Int; + ret.Int = Operator == '+'? v1 + v2 : + Operator == '-'? v1 - v2 : 0; + + } + return ret; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxMulDiv::FxMulDiv(int o, FxExpression *l, FxExpression *r) +: FxBinary(o, l, r) +{ +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + + if (!ResolveLR(ctx, true)) return NULL; + + if (left->isConstant() && right->isConstant()) + { + if (ValueType == VAL_Float) + { + double v; + double v1 = left->EvalExpression(NULL, ctx.cls).GetFloat(); + double v2 = right->EvalExpression(NULL, ctx.cls).GetFloat(); + + if (Operator != '*' && v2 == 0) + { + ScriptPosition.Message(MSG_ERROR, "Division by 0"); + delete this; + return NULL; + } + + v = Operator == '*'? v1 * v2 : + Operator == '/'? v1 / v2 : + Operator == '%'? fmod(v1, v2) : 0; + + FxExpression *e = new FxConstant(v, ScriptPosition); + delete this; + return e; + } + else + { + int v; + int v1 = left->EvalExpression(NULL, ctx.cls).GetInt(); + int v2 = right->EvalExpression(NULL, ctx.cls).GetInt(); + + if (Operator != '*' && v2 == 0) + { + ScriptPosition.Message(MSG_ERROR, "Division by 0"); + delete this; + return NULL; + } + + v = Operator == '*'? v1 * v2 : + Operator == '/'? v1 / v2 : + Operator == '%'? v1 % v2 : 0; + + FxExpression *e = new FxConstant(v, ScriptPosition); + delete this; + return e; + + } + } + return this; +} + + +//========================================================================== +// +// +// +//========================================================================== + +ExpVal FxMulDiv::EvalExpression (AActor *self, const PClass *cls) +{ + ExpVal ret; + + if (left->ValueType == VAL_Float || right->ValueType ==VAL_Float) + { + double v1 = left->EvalExpression(self, cls).GetFloat(); + double v2 = right->EvalExpression(self, cls).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(self, cls).GetInt(); + int v2 = right->EvalExpression(self, cls).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; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxCompareRel::FxCompareRel(int o, FxExpression *l, FxExpression *r) +: FxBinary(o, l, r) +{ +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + if (!ResolveLR(ctx, true)) return false; + + if (left->isConstant() && right->isConstant()) + { + int v; + + if (ValueType == VAL_Float) + { + double v1 = left->EvalExpression(NULL, ctx.cls).GetFloat(); + double v2 = right->EvalExpression(NULL, ctx.cls).GetFloat(); + v = Operator == '<'? v1 < v2 : + Operator == '>'? v1 > v2 : + Operator == TK_Geq? v1 >= v2 : + Operator == TK_Leq? v1 <= v2 : 0; + } + else + { + int v1 = left->EvalExpression(NULL, ctx.cls).GetInt(); + int v2 = right->EvalExpression(NULL, ctx.cls).GetInt(); + v = Operator == '<'? v1 < v2 : + Operator == '>'? v1 > v2 : + Operator == TK_Geq? v1 >= v2 : + Operator == TK_Leq? v1 <= v2 : 0; + } + FxExpression *e = new FxConstant(v, ScriptPosition); + delete this; + return e; + } + ValueType = VAL_Int; + return this; +} + + +//========================================================================== +// +// +// +//========================================================================== + +ExpVal FxCompareRel::EvalExpression (AActor *self, const PClass *cls) +{ + ExpVal ret; + + ret.Type = VAL_Int; + + if (left->ValueType == VAL_Float || right->ValueType ==VAL_Float) + { + double v1 = left->EvalExpression(self, cls).GetFloat(); + double v2 = right->EvalExpression(self, cls).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(self, cls).GetInt(); + int v2 = right->EvalExpression(self, cls).GetInt(); + ret.Int = Operator == '<'? v1 < v2 : + Operator == '>'? v1 > v2 : + Operator == TK_Geq? v1 >= v2 : + Operator == TK_Leq? v1 <= v2 : 0; + } + return ret; +} + + +//========================================================================== +// +// +// +//========================================================================== + +FxCompareEq::FxCompareEq(int o, FxExpression *l, FxExpression *r) +: FxBinary(o, l, r) +{ +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxCompareEq::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + + if (!ResolveLR(ctx, true)) return false; + + if (!left || !right) + { + delete this; + return NULL; + } + + if (left->isConstant() && right->isConstant()) + { + int v; + + if (ValueType == VAL_Float) + { + double v1 = left->EvalExpression(NULL, ctx.cls).GetFloat(); + double v2 = right->EvalExpression(NULL, ctx.cls).GetFloat(); + v = Operator == TK_Eq? v1 == v2 : v1 != v2; + } + else + { + int v1 = left->EvalExpression(NULL, ctx.cls).GetInt(); + int v2 = right->EvalExpression(NULL, ctx.cls).GetInt(); + v = Operator == TK_Eq? v1 == v2 : v1 != v2; + } + FxExpression *e = new FxConstant(v, ScriptPosition); + delete this; + return e; + } + ValueType = VAL_Int; + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpVal FxCompareEq::EvalExpression (AActor *self, const PClass *cls) +{ + ExpVal ret; + + ret.Type = VAL_Int; + + if (left->ValueType == VAL_Float || right->ValueType ==VAL_Float) + { + double v1 = left->EvalExpression(self, cls).GetFloat(); + double v2 = right->EvalExpression(self, cls).GetFloat(); + ret.Int = Operator == TK_Eq? v1 == v2 : v1 != v2; + } + else + { + int v1 = left->EvalExpression(self, cls).GetInt(); + int v2 = right->EvalExpression(self, cls).GetInt(); + ret.Int = Operator == TK_Eq? v1 == v2 : v1 != v2; + } + return ret; +} + + +//========================================================================== +// +// +// +//========================================================================== + +FxBinaryInt::FxBinaryInt(int o, FxExpression *l, FxExpression *r) +: FxBinary(o, l, r) +{ + ValueType = VAL_Int; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + if (!ResolveLR(ctx, false)) return false; + + /* later! DECORATE doesn't do proper type checks + if (lax) + { + if (left->ValueType == VAL_Float) left = new FxIntCast(left); + if (right->ValueType == VAL_Float) right = new FxIntCast(right); + } + + if (left->ValueType != VAL_Int || right->->ValueType != VAL_Int) + { + ScriptPosition.Message(MSG_ERROR, "Type mismatch in expression"); + delete this; + return NULL; + } + */ + + if (left->isConstant() && right->isConstant()) + { + int v1 = left->EvalExpression(NULL, ctx.cls).GetInt(); + int v2 = right->EvalExpression(NULL, ctx.cls).GetInt(); + + FxExpression *e = new FxConstant( + 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, ScriptPosition); + + delete this; + return e; + } + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpVal FxBinaryInt::EvalExpression (AActor *self, const PClass *cls) +{ + int v1 = left->EvalExpression(self, cls).GetInt(); + int v2 = right->EvalExpression(self, cls).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; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxBinaryLogical::FxBinaryLogical(int o, FxExpression *l, FxExpression *r) +: FxExpression(l->ScriptPosition) +{ + Operator=o; + left=l; + right=r; + ValueType = VAL_Int; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxBinaryLogical::~FxBinaryLogical() +{ + SAFE_DELETE(left); + SAFE_DELETE(right); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + if (left) left = left->ResolveAsBoolean(ctx); + if (right) right = right->ResolveAsBoolean(ctx); + if (!left || !right) + { + delete this; + return NULL; + } + + int b_left=-1, b_right=-1; + + if (left->isConstant()) b_left = left->EvalExpression(NULL, ctx.cls).GetBool(); + if (right->isConstant()) b_right = right->EvalExpression(NULL, ctx.cls).GetBool(); + + // Do some optimizations. This will throw out all sub-expressions that are not + // needed to retrieve the final result. + if (Operator == TK_AndAnd) + { + if (b_left==0 || b_right==0) + { + FxExpression *x = new FxConstant(0, ScriptPosition); + delete this; + return x; + } + else if (b_left==1 && b_right==1) + { + FxExpression *x = new FxConstant(1, ScriptPosition); + delete this; + return x; + } + else if (b_left==1) + { + FxExpression *x = right; + right=NULL; + delete this; + return x; + } + else if (b_right==1) + { + FxExpression *x = left; + left=NULL; + delete this; + return x; + } + } + else if (Operator == TK_OrOr) + { + if (b_left==1 || b_right==1) + { + FxExpression *x = new FxConstant(1, ScriptPosition); + delete this; + return x; + } + if (b_left==0 && b_right==0) + { + FxExpression *x = new FxConstant(0, ScriptPosition); + delete this; + return x; + } + else if (b_left==0) + { + FxExpression *x = right; + right=NULL; + delete this; + return x; + } + else if (b_right==0) + { + FxExpression *x = left; + left=NULL; + delete this; + return x; + } + } + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpVal FxBinaryLogical::EvalExpression (AActor *self, const PClass *cls) +{ + bool b_left = left->EvalExpression(self, cls).GetBool(); + ExpVal ret; + + ret.Type = VAL_Int; + ret.Int = false; + + if (Operator == TK_AndAnd) + { + ret.Int = (b_left && right->EvalExpression(self, cls).GetBool()); + } + else if (Operator == TK_OrOr) + { + ret.Int = (b_left || right->EvalExpression(self, cls).GetBool()); + } + return ret; +} + + +//========================================================================== +// +// +// +//========================================================================== + +FxConditional::FxConditional(FxExpression *c, FxExpression *t, FxExpression *f) +: FxExpression(c->ScriptPosition) +{ + condition = c; + truex=t; + falsex=f; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxConditional::~FxConditional() +{ + SAFE_DELETE(condition); + SAFE_DELETE(truex); + SAFE_DELETE(falsex); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxConditional::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + if (condition) condition = condition->ResolveAsBoolean(ctx); + RESOLVE(truex, ctx); + RESOLVE(falsex, ctx); + ABORT(condition && truex && falsex); + + if (truex->ValueType == VAL_Int && falsex->ValueType == VAL_Int) + ValueType = VAL_Int; + else + ValueType = VAL_Float; + + if (condition->isConstant()) + { + ExpVal condval = condition->EvalExpression(NULL, ctx.cls); + bool result = condval.GetBool(); + + FxExpression *e = result? truex:falsex; + delete (result? falsex:truex); + falsex = truex = NULL; + delete this; + return e; + } + + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpVal FxConditional::EvalExpression (AActor *self, const PClass *cls) +{ + ExpVal condval = condition->EvalExpression(self, cls); + bool result = condval.GetBool(); + + FxExpression *e = result? truex:falsex; + return e->EvalExpression(self, cls); +} + +//========================================================================== +// +// +// +//========================================================================== +FxAbs::FxAbs(FxExpression *v) +: FxExpression(v->ScriptPosition) +{ + val = v; + Type = VAL_Int; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxAbs::~FxAbs() +{ + SAFE_DELETE(val); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxAbs::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(val, ctx); + + if (val->isConstant()) + { + ExpVal value = val->EvalExpression(NULL, ctx.cls); + switch (value.Type) + { + case VAL_Int: + value.Int = abs(value.Int); + break; + + case VAL_Float: + value.Float = fabs(value.Float); + + default: + // shouldn't happen + delete this; + return NULL; + } + FxExpression *x = new FxConstant(value, ScriptPosition); + delete this; + return x; + } + ValueType = val->ValueType; + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpVal FxAbs::EvalExpression (AActor *self, const PClass *cls) +{ + ExpVal value = val->EvalExpression(self, cls); + switch (value.Type) + { + default: + case VAL_Int: + value.Int = abs(value.Int); + break; + + case VAL_Float: + value.Float = fabs(value.Float); + break; + } + return value; +} + +//========================================================================== +// +// +// +//========================================================================== +FxRandom::FxRandom(FRandom * r, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos) +: FxExpression(pos) +{ + rng = r; + if (min && max) + { + min = new FxIntCast(mi); + max = new FxIntCast(ma); + } + else + { + SAFE_DELETE(mi); + SAFE_DELETE(ma); + min = max = NULL; + } + ValueType = VAL_Int; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxRandom::~FxRandom() +{ + SAFE_DELETE(min); + SAFE_DELETE(max); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxRandom::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + if (min && max) + { + RESOLVE(min, ctx); + RESOLVE(max, ctx); + ABORT(min && max); + } + return this; +}; + + +//========================================================================== +// +// +// +//========================================================================== + +ExpVal FxRandom::EvalExpression (AActor *self, const PClass *cls) +{ + int minval = min->EvalExpression (self, cls).GetInt(); + int maxval = max->EvalExpression (self, cls).GetInt(); + + ExpVal val; + val.Type = VAL_Int; + + if (maxval < minval) + { + swap (maxval, minval); + } + + val.Int = (*rng)(maxval - minval + 1) + minval; + return val; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxRandom2::FxRandom2(FRandom *r, FxExpression *m, const FScriptPosition &pos) +: FxExpression(pos) +{ + rng = r; + if (m) mask = new FxIntCast(m); + else mask = new FxConstant(-1, pos); + ValueType = VAL_Int; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxRandom2::~FxRandom2() +{ + SAFE_DELETE(mask); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxRandom2::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(mask, ctx); + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpVal FxRandom2::EvalExpression (AActor *self, const PClass *cls) +{ + ExpVal maskval = mask->EvalExpression(self, cls); + int imaskval = maskval.GetInt(); + + maskval.Type = VAL_Int; + maskval.Int = rng->Random2(imaskval); + return maskval; +} diff --git a/src/thingdef/thingdef_main.cpp b/src/thingdef/thingdef_main.cpp index 85513e1564..55fe386a66 100644 --- a/src/thingdef/thingdef_main.cpp +++ b/src/thingdef/thingdef_main.cpp @@ -51,6 +51,7 @@ void FinishThingdef(); void ParseOldDecoration(FScanner &sc, EDefinitionType def); // STATIC FUNCTION PROTOTYPES -------------------------------------------- +PSymbolTable GlobalSymbols; //========================================================================== // @@ -82,11 +83,11 @@ static void ParseDecorate (FScanner &sc) } case TK_Const: - ParseConstant (sc, &RUNTIME_CLASS(AActor)->Symbols, RUNTIME_CLASS(AActor)); + ParseConstant (sc, &GlobalSymbols, RUNTIME_CLASS(AActor)); break; case TK_Enum: - ParseEnum (sc, &RUNTIME_CLASS(AActor)->Symbols, RUNTIME_CLASS(AActor)); + ParseEnum (sc, &GlobalSymbols, RUNTIME_CLASS(AActor)); break; case TK_Pickup: diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 557bee5c7d..a9db54cc22 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -50,6 +50,7 @@ #include "doomerrors.h" #include "autosegs.h" #include "i_system.h" +#include "thingdef_exp.h" //========================================================================== @@ -68,10 +69,11 @@ void ParseConstant (FScanner &sc, PSymbolTable * symt, PClass *cls) sc.MustGetToken(TK_Identifier); FName symname = sc.String; sc.MustGetToken('='); - int expr = ParseExpression (sc, false, cls); + FxExpression *expr = ParseExpression (sc, cls); sc.MustGetToken(';'); - int val = EvalExpressionI (expr, NULL, cls); + int val = expr->EvalExpression(NULL, cls).GetInt(); + delete expr; PSymbolConst *sym = new PSymbolConst; sym->SymbolName = symname; sym->SymbolType = SYM_Const; @@ -79,8 +81,8 @@ void ParseConstant (FScanner &sc, PSymbolTable * symt, PClass *cls) if (symt->AddSymbol (sym) == NULL) { delete sym; - sc.ScriptError ("'%s' is already defined in class '%s'.", - symname.GetChars(), cls->TypeName.GetChars()); + sc.ScriptError ("'%s' is already defined in '%s'.", + symname.GetChars(), cls? cls->TypeName.GetChars() : "Global"); } } @@ -103,8 +105,9 @@ void ParseEnum (FScanner &sc, PSymbolTable *symt, PClass *cls) FName symname = sc.String; if (sc.CheckToken('=')) { - int expr = ParseExpression(sc, false, cls); - currvalue = EvalExpressionI(expr, NULL, cls); + FxExpression *expr = ParseExpression (sc, cls); + currvalue = expr->EvalExpression(NULL, cls).GetInt(); + delete expr; } PSymbolConst *sym = new PSymbolConst; sym->SymbolName = symname; @@ -113,8 +116,8 @@ void ParseEnum (FScanner &sc, PSymbolTable *symt, PClass *cls) if (symt->AddSymbol (sym) == NULL) { delete sym; - sc.ScriptError ("'%s' is already defined in class '%s'.", - symname.GetChars(), cls->TypeName.GetChars()); + sc.ScriptError ("'%s' is already defined in '%s'.", + symname.GetChars(), cls? cls->TypeName.GetChars() : "Global"); } // This allows a comma after the last value but doesn't enforce it. if (sc.CheckToken('}')) break; diff --git a/zdoom.vcproj b/zdoom.vcproj index a8d235bc98..02cbb6cad0 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -1063,6 +1063,14 @@ RelativePath=".\src\thingdef\thingdef_exp.cpp" > + + + +