- Added dummy code generation for states that pass parameters to action functions.

Currently, they're only good for disassembly and pasting into a proper text editor
  for viewing.
- Fixed some problems with the FxExpression emitters that were revealed by actually
  using them on the standard actors.

SVN r1911 (scripting)
This commit is contained in:
Randy Heit 2009-10-15 03:58:23 +00:00
parent 4fa94390d0
commit 85cc335725
11 changed files with 250 additions and 85 deletions

View file

@ -611,8 +611,6 @@ enum MBFCodePointers
SMMU_NailBomb, // No misc, but it's basically A_Explode with an added effect
};
int PrepareStateParameters(FState * state, int numparams, const PClass *cls);// Should probably be in a .h file.
// Hacks the parameter list for the given state so as to convert MBF-args (misc1 and misc2) into real args.
void SetDehParams(FState * state, int codepointer)
@ -636,6 +634,7 @@ void SetDehParams(FState * state, int codepointer)
// Bleargh! This will all have to be redone once scripting works
// Not sure exactly why the index for a state is greater by one point than the index for a symbol.
#if 0
DPrintf("SetDehParams: Paramindex is %d, default is %d.\n",
state->ParameterIndex-1, sym->defaultparameterindex);
if (state->ParameterIndex-1 == sym->defaultparameterindex)
@ -716,6 +715,7 @@ void SetDehParams(FState * state, int codepointer)
// This simply should not happen.
Printf("Unmanaged dehacked codepointer alias num %i\n", codepointer);
}
#endif
}
static int PatchThing (int thingy)

View file

@ -817,13 +817,16 @@ bool FStateDefinitions::SetLoop()
//==========================================================================
//
// AddStates
// adds some state to the current definition set
//
// Adds some state to the current definition set. Returns the number of
// states added. Positive = no errors, negative = errors.
//
//==========================================================================
bool FStateDefinitions::AddStates(FState *state, const char *framechars)
int FStateDefinitions::AddStates(FState *state, const char *framechars)
{
bool error = false;
int count = 0;
while (*framechars)
{
int frame;
@ -842,9 +845,10 @@ bool FStateDefinitions::AddStates(FState *state, const char *framechars)
state->Frame = (state->Frame&(SF_FULLBRIGHT)) | frame;
StateArray.Push(*state);
++count;
}
laststate = &StateArray[StateArray.Size() - 1];
return !error;
return !error ? count : -count;
}
//==========================================================================

View file

@ -64,6 +64,7 @@
#include "thingdef.h"
#include "thingdef_exp.h"
#include "a_sharedglobal.h"
#include "vmbuilder.h"
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
void InitThingdef();
@ -279,8 +280,42 @@ void FinishActor(const FScriptPosition &sc, FActorInfo *info, Baggage &bag)
static void FinishThingdef()
{
int errorcount = StateParams.ResolveAll();
unsigned i, j;
for (unsigned i = 0;i < PClass::m_Types.Size(); i++)
for (i = 0; i < StateTempCalls.Size(); ++i)
{
FStateTempCall *tcall = StateTempCalls[i];
FCompileContext ctx(tcall->ActorInfo->Class, true);
for (j = 0; j < tcall->Parameters.Size(); ++j)
{
tcall->Parameters[j]->Resolve(ctx);
}
VMFunctionBuilder buildit;
for (j = 0; j < tcall->Parameters.Size(); ++j)
{
FxExpression *p = /*new FxParameter*/(tcall->Parameters[j]);
p->Emit(&buildit);
delete p;
}
// FIXME: Call a real function
buildit.Emit(OP_CALL_K, buildit.GetConstantAddress(NULL, ATAG_OBJECT), j, 0);
VMScriptFunction *func = buildit.MakeFunction();
#if 1
const char *marks = "=======================================================";
char label[40];
int labellen = mysnprintf(label, countof(label), "Function %s.States[%d] (*%d)",
tcall->ActorInfo->Class->TypeName.GetChars(),
tcall->FirstState, tcall->NumStates);
Printf("\n%.*s %s %.*s", MAX(3, 38 - labellen / 2), marks, label, MAX(3, 38 - labellen / 2), marks);
VMDumpConstants(func);
Printf("\nDisassembly:\n");
VMDisasm(func->Code, func->NumCodeBytes / 4, func);
#endif
//if(i==6) I_Error("Poop");
}
I_Error("Poop");
for (i = 0; i < PClass::m_Types.Size(); i++)
{
PClass * ti = PClass::m_Types[i];

View file

@ -99,9 +99,8 @@ public:
bool SetStop();
bool SetWait();
bool SetLoop();
bool AddStates(FState *state, const char *framechars);
int AddStates(FState *state, const char *framechars);
int GetStateCount() const { return StateArray.Size(); }
};
//==========================================================================
@ -110,6 +109,15 @@ public:
//
//==========================================================================
struct FStateTempCall
{
FActorInfo *ActorInfo;
int FirstState;
int NumStates;
TArray<FxExpression *> Parameters;
};
extern TDeletingArray<FStateTempCall *> StateTempCalls;
struct FStateExpression
{
FxExpression *expr;

View file

@ -314,6 +314,7 @@ public:
return true;
}
ExpVal EvalExpression (AActor *self);
ExpEmit Emit(VMFunctionBuilder *build);
};
@ -439,7 +440,7 @@ public:
FxBinary(int, FxExpression*, FxExpression*);
~FxBinary();
bool ResolveLR(FCompileContext& ctx, bool castnumeric);
void Promote();
void Promote(FCompileContext &ctx);
};
//==========================================================================

View file

@ -79,7 +79,7 @@ DEFINE_MEMBER_VARIABLE(Score, AActor)
DEFINE_MEMBER_VARIABLE(uservar, AActor)
ExpEmit::ExpEmit(VMFunctionBuilder *build, int type)
: RegNum(build->Registers[type].Get(1)), RegType(type)
: RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false)
{
}
@ -371,7 +371,7 @@ ExpEmit FxParameter::Emit(VMFunctionBuilder *build)
}
else if (val.Type == VAL_Float)
{
build->Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, build->GetConstantFloat(val.Int));
build->Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, build->GetConstantFloat(val.Float));
}
else if (val.Type == VAL_Class || val.Type == VAL_Object)
{
@ -390,11 +390,15 @@ ExpEmit FxParameter::Emit(VMFunctionBuilder *build)
{
ExpEmit where = Operand->Emit(build);
if (where.RegNum == REGT_NIL)
if (where.RegType == REGT_NIL)
{
ScriptPosition.Message(MSG_ERROR, "Attempted to pass a non-value");
build->Emit(OP_PARAM, 0, where.RegType, where.RegNum);
}
else
{
build->Emit(OP_PARAM, 0, where.RegType, where.RegNum);
}
}
return ExpEmit();
}
@ -445,6 +449,40 @@ FxExpression *FxConstant::MakeConstant(PSymbol *sym, const FScriptPosition &pos)
return x;
}
ExpEmit FxConstant::Emit(VMFunctionBuilder *build)
{
ExpEmit out;
out.Konst = true;
if (value.Type == VAL_Int || value.Type == VAL_Sound || value.Type == VAL_Name || value.Type == VAL_Color)
{
out.RegType = REGT_INT;
out.RegNum = build->GetConstantInt(value.Int);
}
else if (value.Type == VAL_Float)
{
out.RegType = REGT_FLOAT;
out.RegNum = build->GetConstantFloat(value.Float);
}
else if (value.Type == VAL_Class || value.Type == VAL_Object)
{
out.RegType = REGT_POINTER;
out.RegNum = build->GetConstantAddress(value.pointer, ATAG_OBJECT);
}
else if (value.Type == VAL_State)
{
out.RegType = REGT_POINTER;
out.RegNum = build->GetConstantAddress(value.pointer, ATAG_STATE);
}
else
{
ScriptPosition.Message(MSG_ERROR, "Cannot emit needed constant");
out.RegType = REGT_NIL;
out.RegNum = 0;
}
return out;
}
//==========================================================================
//
//
@ -610,6 +648,7 @@ ExpEmit FxFloatCast::Emit(VMFunctionBuilder *build)
ExpEmit from = basex->Emit(build);
assert(!from.Konst);
assert(basex->ValueType == VAL_Int);
build->FreeReg(from.RegType, from.RegNum);
ExpEmit to(build, REGT_FLOAT);
build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_I2F);
return to;
@ -1033,15 +1072,15 @@ bool FxBinary::ResolveLR(FCompileContext& ctx, bool castnumeric)
return true;
}
void FxBinary::Promote()
void FxBinary::Promote(FCompileContext &ctx)
{
if (left->ValueType == VAL_Float && right->ValueType == VAL_Int)
{
right = new FxFloatCast(right);
right = (new FxFloatCast(right))->Resolve(ctx);
}
else if (left->ValueType == VAL_Int && right->ValueType == VAL_Float)
{
left = new FxFloatCast(left);
left = (new FxFloatCast(left))->Resolve(ctx);
}
}
@ -1103,7 +1142,7 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx)
}
}
Promote();
Promote(ctx);
return this;
}
@ -1280,7 +1319,7 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx)
}
}
Promote();
Promote(ctx);
return this;
}
@ -1342,6 +1381,7 @@ ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build)
swap(op1, op2);
}
assert(!op1.Konst);
build->FreeReg(op1.RegType, op1.RegNum);
if (!op2.Konst)
{
build->FreeReg(op2.RegType, op2.RegNum);
@ -1451,7 +1491,7 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx)
delete this;
return e;
}
Promote();
Promote(ctx);
ValueType = VAL_Int;
return this;
}
@ -1604,7 +1644,7 @@ cont:
delete this;
return e;
}
Promote();
Promote(ctx);
ValueType = VAL_Int;
return this;
}
@ -2357,6 +2397,14 @@ FxExpression *FxRandom::Resolve(FCompileContext &ctx)
CHECKRESOLVED();
if (min && max)
{
if (min->ValueType != VAL_Int)
{
min = new FxIntCast(min);
}
if (max->ValueType != VAL_Int)
{
max = new FxIntCast(max);
}
RESOLVE(min, ctx);
RESOLVE(max, ctx);
ABORT(min && max);

View file

@ -56,18 +56,7 @@
#include "colormatcher.h"
#include "thingdef_exp.h"
//==========================================================================
//***
// PrepareStateParameters
// creates an empty parameter list for a parameterized function call
//
//==========================================================================
int PrepareStateParameters(FState * state, int numparams, const PClass *cls)
{
int paramindex=StateParams.Reserve(numparams, cls);
state->ParameterIndex = paramindex+1;
return paramindex;
}
TDeletingArray<FStateTempCall *> StateTempCalls;
//==========================================================================
//***
@ -75,7 +64,7 @@ int PrepareStateParameters(FState * state, int numparams, const PClass *cls)
// handles action specials as code pointers
//
//==========================================================================
bool DoActionSpecials(FScanner &sc, FState & state, Baggage &bag)
bool DoActionSpecials(FScanner &sc, FState & state, Baggage &bag, FStateTempCall *tcall)
{
int i;
int min_args, max_args;
@ -85,17 +74,14 @@ bool DoActionSpecials(FScanner &sc, FState & state, Baggage &bag)
if (special > 0 && min_args >= 0)
{
int paramindex=PrepareStateParameters(&state, 6, bag.Info->Class);
StateParams.Set(paramindex, new FxConstant(special, sc));
tcall->Parameters.Push(new FxParameter(new FxConstant(special, sc)));
// Make this consistent with all other parameter parsing
if (sc.CheckToken('('))
{
for (i = 0; i < 5;)
{
StateParams.Set(paramindex+i+1, ParseExpression (sc, bag.Info->Class));
tcall->Parameters.Push(new FxParameter(ParseExpression(sc, bag.Info->Class)));
i++;
if (!sc.CheckToken (',')) break;
}
@ -154,6 +140,7 @@ void ParseStates(FScanner &sc, FActorInfo * actor, AActor * defaults, Baggage &b
FString statestring;
FState state;
char lastsprite[5] = "";
FStateTempCall *tcall = NULL;
sc.MustGetStringName ("{");
sc.SetEscape(false); // disable escape sequences in the state parser
@ -238,6 +225,10 @@ do_stop:
sc.MustGetNumber();
state.Tics = clamp<int>(sc.Number, -1, 32767);
if (tcall == NULL)
{
tcall = new FStateTempCall;
}
while (sc.GetString() && !sc.Crossed)
{
@ -262,7 +253,7 @@ do_stop:
// Make the action name lowercase to satisfy the gperf hashers
strlwr (sc.String);
if (DoActionSpecials(sc, state, bag))
if (DoActionSpecials(sc, state, bag, tcall))
{
goto endofstate;
}
@ -292,19 +283,19 @@ do_stop:
}
}
int paramindex = PrepareStateParameters(&state, numparams, bag.Info->Class);
int paramstart = paramindex;
// int paramindex = PrepareStateParameters(&state, numparams, bag.Info->Class);
// int paramstart = paramindex;
bool varargs = params[numparams - 1] == '+';
int varargcount=0;
int argcount = 0;
if (varargs)
{
paramindex++;
// paramindex++;
}
else if (afd->defaultparameterindex > -1)
{
StateParams.Copy(paramindex, afd->defaultparameterindex, int(afd->Arguments.Len()));
// StateParams.Copy(paramindex, afd->defaultparameterindex, int(afd->Arguments.Len()));
}
while (*params)
@ -338,19 +329,17 @@ do_stop:
// Use the generic parameter parser for everything else
x = ParseParameter(sc, bag.Info->Class, *params, false);
}
StateParams.Set(paramindex++, x);
// StateParams.Set(paramindex++, x);
tcall->Parameters.Push(new FxParameter(x));
params++;
if (varargs)
{
varargcount++;
}
argcount++;
if (*params)
{
if (*params == '+')
{
if (sc.CheckString(")"))
{
StateParams.Set(paramstart, new FxConstant(varargcount, sc));
// StateParams.Set(paramstart, new FxConstant(argcount, sc));
goto endofstate;
}
params--;
@ -380,12 +369,26 @@ do_stop:
}
sc.UnGet();
endofstate:
if (!bag.statedef.AddStates(&state, statestring))
int count = bag.statedef.AddStates(&state, statestring);
if (count < 0)
{
sc.ScriptError ("Invalid frame character string '%s'", statestring.GetChars());
count = -count;
}
if (tcall->Parameters.Size() != 0)
{
tcall->ActorInfo = actor;
tcall->FirstState = bag.statedef.GetStateCount() - count;
tcall->NumStates = count;
StateTempCalls.Push(tcall);
tcall = NULL;
}
}
}
if (tcall != NULL)
{
delete tcall;
}
sc.SetEscape(true); // re-enable escape sequences
}

View file

@ -812,6 +812,7 @@ void VMSelectEngine(EVMEngine engine);
extern int (*VMExec)(VMFrameStack *stack, const VM_UBYTE *pc, VMReturn *ret, int numret);
void VMFillParams(VMValue *params, VMFrame *callee, int numparam);
void VMDumpConstants(const VMScriptFunction *func);
void VMDisasm(const VM_UBYTE *code, int codesize, const VMScriptFunction *func);
#endif

View file

@ -227,6 +227,10 @@ int VMFunctionBuilder::GetConstantString(FString val)
int VMFunctionBuilder::GetConstantAddress(void *ptr, VM_ATAG tag)
{
if (ptr == NULL)
{ // Make all NULL pointers generic. (Or should we allow typed NULLs?)
tag = ATAG_GENERIC;
}
AddrKonst *locp = AddressConstants.CheckKey(ptr);
if (locp != NULL)
{

View file

@ -51,7 +51,7 @@ public:
RegAvailability Registers[4];
// Free a register.
void FreeReg(int regtype, int regnum);
void FreeReg(int regtype, int regnum) { Registers[regtype].Return(regnum, 1); }
private:
struct AddrKonst

View file

@ -101,6 +101,63 @@ const VMOpInfo OpInfo[NUM_OPS] =
static int print_reg(int col, int arg, int mode, int immshift, const VMScriptFunction *func);
void VMDumpConstants(const VMScriptFunction *func)
{
char tmp[21];
int i, j, k, kk;
if (func->KonstD != NULL && func->NumKonstD != 0)
{
Printf("\nConstant integers:\n");
kk = (func->NumKonstD + 3) / 4;
for (i = 0; i < kk; ++i)
{
for (j = 0, k = i; j < 4 && k < func->NumKonstD; j++, k += kk)
{
mysnprintf(tmp, countof(tmp), "%3d. %d", k, func->KonstD[k]);
Printf("%-20s", tmp);
}
Printf("\n");
}
}
if (func->KonstF != NULL && func->NumKonstF != 0)
{
Printf("\nConstant floats:\n");
kk = (func->NumKonstF + 3) / 4;
for (i = 0; i < kk; ++i)
{
for (j = 0, k = i; j < 4 && k < func->NumKonstF; j++, k += kk)
{
mysnprintf(tmp, countof(tmp), "%3d. %.16f", k, func->KonstF[k]);
Printf("%-20s", tmp);
}
Printf("\n");
}
}
if (func->KonstA != NULL && func->NumKonstA != 0)
{
Printf("\nConstant addresses:\n");
kk = (func->NumKonstA + 3) / 4;
for (i = 0; i < kk; ++i)
{
for (j = 0, k = i; j < 4 && k < func->NumKonstA; j++, k += kk)
{
mysnprintf(tmp, countof(tmp), "%3d. %p", k, func->KonstA[k]);
Printf("%-20s", tmp);
}
Printf("\n");
}
}
if (func->KonstS != NULL && func->NumKonstS != 0)
{
Printf("\nConstant strings:\n");
for (i = 0; i < func->NumKonstS; ++i)
{
Printf("%3d. %s\n", func->KonstS[k].GetChars());
}
}
}
void VMDisasm(const VM_UBYTE *code, int codesize, const VMScriptFunction *func)
{
const char *name;
@ -129,13 +186,13 @@ void VMDisasm(const VM_UBYTE *code, int codesize, const VMScriptFunction *func)
a &= CMP_CHECK | CMP_APPROX;
}
printf("%08x: %02x%02x%02x%02x %-8s", i, code[i], code[i+1], code[i+2], code[i+3], name);
Printf("%08x: %02x%02x%02x%02x %-8s", i, code[i], code[i+1], code[i+2], code[i+3], name);
col = 0;
switch (code[i])
{
case OP_JMP:
case OP_TRY:
col = printf("%08x", i + 4 + JMPOFS(&code[i]));
col = Printf("%08x", i + 4 + JMPOFS(&code[i]));
break;
case OP_RET:
@ -151,7 +208,7 @@ void VMDisasm(const VM_UBYTE *code, int codesize, const VMScriptFunction *func)
col += print_reg(col, *(VM_UHALF *)&code[i+2], MODE_PARAM, 16, func);
if (code[i+2] & REGT_FINAL)
{
col += printf(" [final]");
col += Printf(" [final]");
}
}
}
@ -229,14 +286,14 @@ void VMDisasm(const VM_UBYTE *code, int codesize, const VMScriptFunction *func)
{
col = 30;
}
printf("%*c", 30 - col, ';');
Printf("%*c", 30 - col, ';');
if (code[i] == OP_JMP || code[i] == OP_TRY)
{
printf("%d\n", JMPOFS(&code[i]) >> 2);
Printf("%d\n", JMPOFS(&code[i]) >> 2);
}
else
{
printf("%d,%d,%d\n", code[i+1], code[i+2], code[i+3]);
Printf("%d,%d,%d\n", code[i+1], code[i+2], code[i+3]);
}
}
}
@ -249,57 +306,57 @@ static int print_reg(int col, int arg, int mode, int immshift, const VMScriptFun
}
if (col > 0)
{
col = printf(",");
col = Printf(",");
}
switch(mode)
{
case MODE_I:
return col+printf("d%d", arg);
return col+Printf("d%d", arg);
case MODE_F:
return col+printf("f%d", arg);
return col+Printf("f%d", arg);
case MODE_S:
return col+printf("s%d", arg);
return col+Printf("s%d", arg);
case MODE_P:
return col+printf("a%d", arg);
return col+Printf("a%d", arg);
case MODE_V:
return col+printf("v%d", arg);
return col+Printf("v%d", arg);
case MODE_KI:
if (func != NULL)
{
return col+printf("%d", func->KonstD[arg]);
return col+Printf("%d", func->KonstD[arg]);
}
return printf("kd%d", arg);
return Printf("kd%d", arg);
case MODE_KF:
if (func != NULL)
{
return col+printf("%f", func->KonstF[arg]);
return col+Printf("%f", func->KonstF[arg]);
}
return col+printf("kf%d", arg);
return col+Printf("kf%d", arg);
case MODE_KS:
if (func != NULL)
{
return col+printf("\"%s\"", func->KonstS[arg].GetChars());
return col+Printf("\"%s\"", func->KonstS[arg].GetChars());
}
return col+printf("ks%d", arg);
return col+Printf("ks%d", arg);
case MODE_KP:
if (func != NULL)
{
return col+printf("%p", func->KonstA[arg]);
return col+Printf("%p", func->KonstA[arg]);
}
return col+printf("ka%d", arg);
return col+Printf("ka%d", arg);
case MODE_KV:
if (func != NULL)
{
return col+printf("(%f,%f,%f)", func->KonstF[arg], func->KonstF[arg+1], func->KonstF[arg+2]);
return col+Printf("(%f,%f,%f)", func->KonstF[arg], func->KonstF[arg+1], func->KonstF[arg+2]);
}
return col+printf("kv%d", arg);
return col+Printf("kv%d", arg);
case MODE_IMMS:
return col+printf("%d", (arg << immshift) >> immshift);
return col+Printf("%d", (arg << immshift) >> immshift);
case MODE_IMMZ:
return col+printf("%d", arg);
return col+Printf("%d", arg);
case MODE_PARAM:
{
@ -308,15 +365,15 @@ static int print_reg(int col, int arg, int mode, int immshift, const VMScriptFun
switch (p.RegType & (REGT_TYPE | REGT_KONST | REGT_MULTIREG))
{
case REGT_INT:
return col+printf("d%d", p.RegNum);
return col+Printf("d%d", p.RegNum);
case REGT_FLOAT:
return col+printf("f%d", p.RegNum);
return col+Printf("f%d", p.RegNum);
case REGT_STRING:
return col+printf("s%d", p.RegNum);
return col+Printf("s%d", p.RegNum);
case REGT_POINTER:
return col+printf("a%d", p.RegNum);
return col+Printf("a%d", p.RegNum);
case REGT_FLOAT | REGT_MULTIREG:
return col+printf("v%d", p.RegNum);
return col+Printf("v%d", p.RegNum);
case REGT_INT | REGT_KONST:
return col+print_reg(0, p.RegNum, MODE_KI, 0, func);
case REGT_FLOAT | REGT_KONST:
@ -328,7 +385,11 @@ static int print_reg(int col, int arg, int mode, int immshift, const VMScriptFun
case REGT_FLOAT | REGT_MULTIREG | REGT_KONST:
return col+print_reg(0, p.RegNum, MODE_KV, 0, func);
default:
return col+printf("param[t=%d,%c,%c,n=%d]",
if (p.RegType == REGT_NIL)
{
return col+Printf("nil");
}
return col+Printf("param[t=%d,%c,%c,n=%d]",
p.RegType & REGT_TYPE,
p.RegType & REGT_KONST ? 'k' : 'r',
p.RegType & REGT_MULTIREG ? 'm' : 's',
@ -337,7 +398,7 @@ static int print_reg(int col, int arg, int mode, int immshift, const VMScriptFun
}
default:
return col+printf("$%d", arg);
return col+Printf("$%d", arg);
}
return col;
}