mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-28 06:53:40 +00:00
- 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)
This commit is contained in:
parent
a4afe79f3d
commit
b455227342
6 changed files with 383 additions and 184 deletions
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
if (!sc.CheckToken(')'))
|
||||
{
|
||||
args = new FArgumentList;
|
||||
do
|
||||
{
|
||||
args->Push(ParseExpressionM (sc, cls));
|
||||
|
||||
}
|
||||
while (sc.CheckToken(','));
|
||||
sc.MustGetToken(')');
|
||||
return data;
|
||||
}
|
||||
else if (identifier == NAME_Cos)
|
||||
return new FxFunctionCall(NULL, identifier, args, sc);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
FxExpression *data = new FxExpression;
|
||||
data->Type = EX_Cos;
|
||||
data->ValueType = VAL_Float;
|
||||
|
||||
data->Children[0] = ParseExpressionM (sc, cls);
|
||||
|
||||
sc.MustGetToken(')');
|
||||
return data;
|
||||
delete args;
|
||||
throw;
|
||||
}
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
FxExpression *right = new FxExpression;
|
||||
right->Type = EX_Right;
|
||||
right->Children[0] = ParseExpressionM (sc, cls);
|
||||
*left = right;
|
||||
left = &right->Children[1];
|
||||
}
|
||||
*left = NULL;
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<FxExpression*> 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);
|
||||
|
|
|
@ -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<AActor>();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue