- 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:
Christoph Oelckers 2008-10-21 18:10:50 +00:00
parent a4afe79f3d
commit b455227342
6 changed files with 383 additions and 184 deletions

View file

@ -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

View file

@ -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"

View file

@ -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;
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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();
}