Add min and max to DECORATE

This commit is contained in:
Randy Heit 2016-02-23 16:26:00 -06:00
parent a8e985f4f6
commit 1ffb7ad109
6 changed files with 248 additions and 12 deletions

View file

@ -191,6 +191,8 @@ std2:
'frandom' { RET(TK_FRandom); }
'randompick' { RET(TK_RandomPick); }
'frandompick' { RET(TK_FRandomPick); }
'min' { RET(TK_Min); }
'max' { RET(TK_Max); }
L (L|D)* { RET(TK_Identifier); }

View file

@ -128,6 +128,8 @@ xx(TK_SizeOf, "'sizeof'")
xx(TK_AlignOf, "'alignof'")
xx(TK_RandomPick, "'randompick'")
xx(TK_FRandomPick, "'frandompick'")
xx(TK_Min, "'min'")
xx(TK_Max, "'max'")
xx(TK_States, "'states'")
xx(TK_Loop, "'loop'")
xx(TK_Fail, "'fail'")

View file

@ -349,6 +349,21 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
// a cheap way to get them working when people use "name" instead of 'name'.
return new FxConstant(FName(sc.String), scpos);
}
else if (sc.CheckToken(TK_Min) || sc.CheckToken(TK_Max))
{
int type = sc.TokenType;
TArray<FxExpression*> list;
sc.MustGetToken('(');
for (;;)
{
FxExpression *expr = ParseExpressionM(sc, cls);
list.Push(expr);
if (sc.CheckToken(')'))
break;
sc.MustGetToken(',');
}
return new FxMinMax(list, type, sc);
}
else if (sc.CheckToken(TK_Random))
{
FRandom *rng;

View file

@ -629,6 +629,24 @@ public:
//
//==========================================================================
class FxMinMax : public FxExpression
{
TDeletingArray<FxExpression *> choices;
int Type;
public:
FxMinMax(TArray<FxExpression*> &expr, int type, const FScriptPosition &pos);
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//
//
//
//==========================================================================
class FxRandom : public FxExpression
{
protected:

View file

@ -2038,6 +2038,214 @@ ExpEmit FxAbs::Emit(VMFunctionBuilder *build)
return out;
}
//==========================================================================
//
//
//
//==========================================================================
FxMinMax::FxMinMax(TArray<FxExpression*> &expr, int type, const FScriptPosition &pos)
: FxExpression(pos), Type(type)
{
assert(expr.Size() > 0);
assert(type == TK_Min || type == TK_Max);
ValueType = VAL_Unknown;
choices.Resize(expr.Size());
for (unsigned i = 0; i < expr.Size(); ++i)
{
choices[i] = expr[i];
}
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxMinMax::Resolve(FCompileContext &ctx)
{
unsigned int i;
bool isconst;
int intcount, floatcount;
CHECKRESOLVED();
// Determine if float or int
intcount = floatcount = 0;
for (i = 0; i < choices.Size(); ++i)
{
RESOLVE(choices[i], ctx);
ABORT(choices[i]);
if (choices[i]->ValueType == VAL_Float)
{
floatcount++;
}
else if (choices[i]->ValueType == VAL_Int)
{
intcount++;
}
else
{
ScriptPosition.Message(MSG_ERROR, "Arguments must be of type int or float");
delete this;
return NULL;
}
}
if (floatcount != 0)
{
ValueType = VAL_Float;
if (intcount != 0)
{ // There are some ints that need to be cast to floats
for (i = 0; i < choices.Size(); ++i)
{
if (choices[i]->ValueType == VAL_Int)
{
choices[i] = new FxFloatCast(choices[i]);
RESOLVE(choices[i], ctx);
ABORT(choices[i]);
}
}
}
}
else
{
ValueType = VAL_Int;
}
// Determine if every argument is constant
isconst = true;
for (i = 0; i < choices.Size(); ++i)
{
if (!choices[i]->isConstant())
{
isconst = false;
break;
}
}
// If every argument is constant, we can decide this now.
if (isconst)
{
ExpVal best = static_cast<FxConstant *>(choices[0])->GetValue();
for (i = 1; i < choices.Size(); ++i)
{
ExpVal value = static_cast<FxConstant *>(choices[i])->GetValue();
assert(value.Type == ValueType.Type);
if (Type == TK_Min)
{
if (value.Type == VAL_Float)
{
if (value.Float < best.Float)
{
best.Float = value.Float;
}
}
else
{
if (value.Int < best.Int)
{
best.Int = value.Int;
}
}
}
else
{
if (value.Type == VAL_Float)
{
if (value.Float > best.Float)
{
best.Float = value.Float;
}
}
else
{
if (value.Int > best.Int)
{
best.Int = value.Int;
}
}
}
}
FxExpression *x = new FxConstant(best, ScriptPosition);
delete this;
return x;
}
return this;
}
//==========================================================================
//
//
//
//==========================================================================
static void EmitLoad(VMFunctionBuilder *build, const ExpEmit resultreg, const ExpVal &value)
{
if (resultreg.RegType == REGT_FLOAT)
{
build->Emit(OP_LKF, resultreg.RegNum, build->GetConstantFloat(value.GetFloat()));
}
else
{
build->EmitLoadInt(resultreg.RegNum, value.GetInt());
}
}
ExpEmit FxMinMax::Emit(VMFunctionBuilder *build)
{
unsigned i;
int opcode, opA;
assert(choices.Size() > 0);
assert(OP_LTF_RK == OP_LTF_RR+1);
assert(OP_LT_RK == OP_LT_RR+1);
assert(OP_LEF_RK == OP_LEF_RR+1);
assert(OP_LE_RK == OP_LE_RR+1);
if (Type == TK_Min)
{
opcode = ValueType.Type == VAL_Float ? OP_LEF_RR : OP_LE_RR;
opA = 1;
}
else
{
opcode = ValueType.Type == VAL_Float ? OP_LTF_RR : OP_LT_RR;
opA = 0;
}
ExpEmit bestreg;
// Get first value into a register. This will also be the result register.
if (choices[0]->isConstant())
{
bestreg = ExpEmit(build, ValueType.Type == VAL_Float ? REGT_FLOAT : REGT_INT);
EmitLoad(build, bestreg, static_cast<FxConstant *>(choices[0])->GetValue());
}
else
{
bestreg = choices[0]->Emit(build);
}
// Compare every choice. Better matches get copied to the bestreg.
for (i = 1; i < choices.Size(); ++i)
{
ExpEmit checkreg = choices[i]->Emit(build);
assert(checkreg.RegType == bestreg.RegType);
build->Emit(opcode + checkreg.Konst, opA, bestreg.RegNum, checkreg.RegNum);
build->Emit(OP_JMP, 1);
if (checkreg.Konst)
{
build->Emit(bestreg.RegType == REGT_FLOAT ? OP_LKF : OP_LK, bestreg.RegNum, checkreg.RegNum);
}
else
{
build->Emit(bestreg.RegType == REGT_FLOAT ? OP_MOVEF : OP_MOVE, bestreg.RegNum, checkreg.RegNum, 0);
checkreg.Free(build);
}
}
return bestreg;
}
//==========================================================================
//
//
@ -2269,16 +2477,7 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build)
build->BackpatchToHere(jumptable + i);
if (choices[i]->isConstant())
{
if (ValueType == VAL_Int)
{
int val = static_cast<FxConstant *>(choices[i])->GetValue().GetInt();
build->EmitLoadInt(resultreg.RegNum, val);
}
else
{
double val = static_cast<FxConstant *>(choices[i])->GetValue().GetFloat();
build->Emit(OP_LKF, resultreg.RegNum, build->GetConstantFloat(val));
}
EmitLoad(build, resultreg, static_cast<FxConstant *>(choices[i])->GetValue());
}
else
{

View file

@ -311,8 +311,8 @@ ACTOR Actor native //: Thinker
action native state A_JumpIfHigherOrLower(state high, state low, float offsethigh = 0, float offsetlow = 0, bool includeHeight = true, int ptr = AAPTR_TARGET);
action native A_SetSpecies(name species, int ptr = AAPTR_DEFAULT);
action native A_SetRipperLevel(int level);
action native A_SetRipMin(int min);
action native A_SetRipMax(int max);
action native A_SetRipMin(int mininum);
action native A_SetRipMax(int maximum);
action native A_SetChaseThreshold(int threshold, bool def = false, int ptr = AAPTR_DEFAULT);
action native state A_CheckProximity(state jump, class<Actor> classname, float distance, int count = 1, int flags = 0, int ptr = AAPTR_DEFAULT);
action native state A_CheckBlock(state block, int flags = 0, int ptr = AAPTR_DEFAULT);