mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-30 16:00:55 +00:00
Added post/pre increment/decrement operators to DECORATE
This commit is contained in:
parent
2ef51d0d50
commit
8437313e7c
5 changed files with 306 additions and 66 deletions
|
@ -18,6 +18,7 @@ typedef std::pair<const class PType *, unsigned> FTypeAndOffset;
|
||||||
#define VARF_Method (1<<1) // func has an implied self parameter
|
#define VARF_Method (1<<1) // func has an implied self parameter
|
||||||
#define VARF_Action (1<<2) // func has implied owner and state parameters
|
#define VARF_Action (1<<2) // func has implied owner and state parameters
|
||||||
#define VARF_Native (1<<3) // func is native code/don't auto serialize field
|
#define VARF_Native (1<<3) // func is native code/don't auto serialize field
|
||||||
|
#define VARF_ReadOnly (1<<4) // field is read only, do not write to it
|
||||||
|
|
||||||
// Symbol information -------------------------------------------------------
|
// Symbol information -------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -631,38 +631,38 @@ void InitThingdef()
|
||||||
// Define some member variables we feel like exposing to the user
|
// Define some member variables we feel like exposing to the user
|
||||||
PSymbolTable &symt = RUNTIME_CLASS(AActor)->Symbols;
|
PSymbolTable &symt = RUNTIME_CLASS(AActor)->Symbols;
|
||||||
PType *array5 = NewArray(TypeSInt32, 5);
|
PType *array5 = NewArray(TypeSInt32, 5);
|
||||||
symt.AddSymbol(new PField(NAME_Alpha, TypeFloat64, VARF_Native, myoffsetof(AActor,Alpha)));
|
symt.AddSymbol(new PField(NAME_Alpha, TypeFloat64, VARF_Native, myoffsetof(AActor, Alpha)));
|
||||||
symt.AddSymbol(new PField(NAME_Angle, TypeFloat64, VARF_Native, myoffsetof(AActor,Angles.Yaw)));
|
symt.AddSymbol(new PField(NAME_Angle, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Yaw)));
|
||||||
symt.AddSymbol(new PField(NAME_Args, array5, VARF_Native, myoffsetof(AActor,args)));
|
symt.AddSymbol(new PField(NAME_Args, array5, VARF_Native, myoffsetof(AActor, args)));
|
||||||
symt.AddSymbol(new PField(NAME_CeilingZ, TypeFloat64, VARF_Native, myoffsetof(AActor,ceilingz)));
|
symt.AddSymbol(new PField(NAME_CeilingZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, ceilingz)));
|
||||||
symt.AddSymbol(new PField(NAME_FloorZ, TypeFloat64, VARF_Native, myoffsetof(AActor,floorz)));
|
symt.AddSymbol(new PField(NAME_FloorZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, floorz)));
|
||||||
symt.AddSymbol(new PField(NAME_Health, TypeSInt32, VARF_Native, myoffsetof(AActor,health)));
|
symt.AddSymbol(new PField(NAME_Health, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, health)));
|
||||||
symt.AddSymbol(new PField(NAME_Mass, TypeSInt32, VARF_Native, myoffsetof(AActor,Mass)));
|
symt.AddSymbol(new PField(NAME_Mass, TypeSInt32, VARF_Native, myoffsetof(AActor, Mass)));
|
||||||
symt.AddSymbol(new PField(NAME_Pitch, TypeFloat64, VARF_Native, myoffsetof(AActor,Angles.Pitch)));
|
symt.AddSymbol(new PField(NAME_Pitch, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Pitch)));
|
||||||
symt.AddSymbol(new PField(NAME_Roll, TypeFloat64, VARF_Native, myoffsetof(AActor,Angles.Roll)));
|
symt.AddSymbol(new PField(NAME_Roll, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Roll)));
|
||||||
symt.AddSymbol(new PField(NAME_Special, TypeSInt32, VARF_Native, myoffsetof(AActor,special)));
|
symt.AddSymbol(new PField(NAME_Special, TypeSInt32, VARF_Native, myoffsetof(AActor, special)));
|
||||||
symt.AddSymbol(new PField(NAME_TID, TypeSInt32, VARF_Native, myoffsetof(AActor,tid)));
|
symt.AddSymbol(new PField(NAME_TID, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, tid)));
|
||||||
symt.AddSymbol(new PField(NAME_TIDtoHate, TypeSInt32, VARF_Native, myoffsetof(AActor,TIDtoHate)));
|
symt.AddSymbol(new PField(NAME_TIDtoHate, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, TIDtoHate)));
|
||||||
symt.AddSymbol(new PField(NAME_WaterLevel, TypeSInt32, VARF_Native, myoffsetof(AActor,waterlevel)));
|
symt.AddSymbol(new PField(NAME_WaterLevel, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, waterlevel)));
|
||||||
symt.AddSymbol(new PField(NAME_X, TypeFloat64, VARF_Native, myoffsetof(AActor,__Pos.X))); // must remain read-only!
|
symt.AddSymbol(new PField(NAME_X, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.X))); // must remain read-only!
|
||||||
symt.AddSymbol(new PField(NAME_Y, TypeFloat64, VARF_Native, myoffsetof(AActor,__Pos.Y))); // must remain read-only!
|
symt.AddSymbol(new PField(NAME_Y, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.Y))); // must remain read-only!
|
||||||
symt.AddSymbol(new PField(NAME_Z, TypeFloat64, VARF_Native, myoffsetof(AActor,__Pos.Z))); // must remain read-only!
|
symt.AddSymbol(new PField(NAME_Z, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.Z))); // must remain read-only!
|
||||||
symt.AddSymbol(new PField(NAME_VelX, TypeFloat64, VARF_Native, myoffsetof(AActor,Vel.X)));
|
symt.AddSymbol(new PField(NAME_VelX, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.X)));
|
||||||
symt.AddSymbol(new PField(NAME_VelY, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Y)));
|
symt.AddSymbol(new PField(NAME_VelY, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Y)));
|
||||||
symt.AddSymbol(new PField(NAME_VelZ, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Z)));
|
symt.AddSymbol(new PField(NAME_VelZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Z)));
|
||||||
symt.AddSymbol(new PField(NAME_MomX, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.X)));
|
symt.AddSymbol(new PField(NAME_MomX, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.X)));
|
||||||
symt.AddSymbol(new PField(NAME_MomY, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Y)));
|
symt.AddSymbol(new PField(NAME_MomY, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Y)));
|
||||||
symt.AddSymbol(new PField(NAME_MomZ, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Z)));
|
symt.AddSymbol(new PField(NAME_MomZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Z)));
|
||||||
symt.AddSymbol(new PField(NAME_ScaleX, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.X)));
|
symt.AddSymbol(new PField(NAME_ScaleX, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.X)));
|
||||||
symt.AddSymbol(new PField(NAME_ScaleY, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.Y)));
|
symt.AddSymbol(new PField(NAME_ScaleY, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.Y)));
|
||||||
symt.AddSymbol(new PField(NAME_Score, TypeSInt32, VARF_Native, myoffsetof(AActor,Score)));
|
symt.AddSymbol(new PField(NAME_Score, TypeSInt32, VARF_Native, myoffsetof(AActor, Score)));
|
||||||
symt.AddSymbol(new PField(NAME_Accuracy, TypeSInt32, VARF_Native, myoffsetof(AActor,accuracy)));
|
symt.AddSymbol(new PField(NAME_Accuracy, TypeSInt32, VARF_Native, myoffsetof(AActor, accuracy)));
|
||||||
symt.AddSymbol(new PField(NAME_Stamina, TypeSInt32, VARF_Native, myoffsetof(AActor,stamina)));
|
symt.AddSymbol(new PField(NAME_Stamina, TypeSInt32, VARF_Native, myoffsetof(AActor, stamina)));
|
||||||
symt.AddSymbol(new PField(NAME_Height, TypeFloat64, VARF_Native, myoffsetof(AActor,Height)));
|
symt.AddSymbol(new PField(NAME_Height, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Height)));
|
||||||
symt.AddSymbol(new PField(NAME_Radius, TypeFloat64, VARF_Native, myoffsetof(AActor,radius)));
|
symt.AddSymbol(new PField(NAME_Radius, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, radius)));
|
||||||
symt.AddSymbol(new PField(NAME_ReactionTime,TypeSInt32, VARF_Native, myoffsetof(AActor,reactiontime)));
|
symt.AddSymbol(new PField(NAME_ReactionTime, TypeSInt32, VARF_Native, myoffsetof(AActor, reactiontime)));
|
||||||
symt.AddSymbol(new PField(NAME_MeleeRange, TypeFloat64, VARF_Native, myoffsetof(AActor,meleerange)));
|
symt.AddSymbol(new PField(NAME_MeleeRange, TypeFloat64, VARF_Native, myoffsetof(AActor, meleerange)));
|
||||||
symt.AddSymbol(new PField(NAME_Speed, TypeFloat64, VARF_Native, myoffsetof(AActor,Speed)));
|
symt.AddSymbol(new PField(NAME_Speed, TypeFloat64, VARF_Native, myoffsetof(AActor, Speed)));
|
||||||
symt.AddSymbol(new PField(NAME_Threshold, TypeSInt32, VARF_Native, myoffsetof(AActor,threshold)));
|
symt.AddSymbol(new PField(NAME_Threshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, threshold)));
|
||||||
symt.AddSymbol(new PField(NAME_DefThreshold,TypeSInt32, VARF_Native, myoffsetof(AActor,DefThreshold)));
|
symt.AddSymbol(new PField(NAME_DefThreshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, DefThreshold)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,7 @@ static FxExpression *ParseClamp(FScanner &sc, PClassActor *cls);
|
||||||
//
|
//
|
||||||
// ParseExpression
|
// ParseExpression
|
||||||
// [GRB] Parses an expression and stores it into Expression array
|
// [GRB] Parses an expression and stores it into Expression array
|
||||||
|
// It's worth mentioning that this is using C++ operator precedence
|
||||||
//
|
//
|
||||||
|
|
||||||
static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls);
|
static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls);
|
||||||
|
@ -257,6 +258,10 @@ static FxExpression *ParseExpressionB (FScanner &sc, PClassActor *cls)
|
||||||
case '+':
|
case '+':
|
||||||
return new FxPlusSign(ParseExpressionA (sc, cls));
|
return new FxPlusSign(ParseExpressionA (sc, cls));
|
||||||
|
|
||||||
|
case TK_Incr:
|
||||||
|
case TK_Decr:
|
||||||
|
return new FxPreIncrDecr(ParseExpressionA(sc, cls), sc.TokenType);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
sc.UnGet();
|
sc.UnGet();
|
||||||
return ParseExpressionA (sc, cls);
|
return ParseExpressionA (sc, cls);
|
||||||
|
@ -312,6 +317,14 @@ static FxExpression *ParseExpressionA (FScanner &sc, PClassActor *cls)
|
||||||
sc.MustGetToken(']');
|
sc.MustGetToken(']');
|
||||||
base_expr = new FxArrayElement(base_expr, index);
|
base_expr = new FxArrayElement(base_expr, index);
|
||||||
}
|
}
|
||||||
|
else if (sc.CheckToken(TK_Incr))
|
||||||
|
{
|
||||||
|
return new FxPostIncrDecr(base_expr, TK_Incr);
|
||||||
|
}
|
||||||
|
else if (sc.CheckToken(TK_Decr))
|
||||||
|
{
|
||||||
|
return new FxPostIncrDecr(base_expr, TK_Decr);
|
||||||
|
}
|
||||||
else break;
|
else break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,7 +491,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new FxIdentifier(identifier, sc);
|
return new FxIdentifier(identifier, sc);
|
||||||
|
|
|
@ -201,7 +201,7 @@ public:
|
||||||
virtual FxExpression *Resolve(FCompileContext &ctx);
|
virtual FxExpression *Resolve(FCompileContext &ctx);
|
||||||
|
|
||||||
virtual bool isConstant() const;
|
virtual bool isConstant() const;
|
||||||
virtual void RequestAddress();
|
virtual bool RequestAddress();
|
||||||
virtual VMFunction *GetDirectFunction();
|
virtual VMFunction *GetDirectFunction();
|
||||||
bool IsNumeric() const { return ValueType != TypeName && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT); }
|
bool IsNumeric() const { return ValueType != TypeName && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT); }
|
||||||
bool IsPointer() const { return ValueType->GetRegType() == REGT_POINTER; }
|
bool IsPointer() const { return ValueType->GetRegType() == REGT_POINTER; }
|
||||||
|
@ -469,6 +469,45 @@ public:
|
||||||
ExpEmit Emit(VMFunctionBuilder *build);
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxPreIncrDecr
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
class FxPreIncrDecr : public FxExpression
|
||||||
|
{
|
||||||
|
int Token;
|
||||||
|
FxExpression *Base;
|
||||||
|
bool AddressRequested;
|
||||||
|
bool AddressWritable;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FxPreIncrDecr(FxExpression *base, int token);
|
||||||
|
~FxPreIncrDecr();
|
||||||
|
FxExpression *Resolve(FCompileContext&);
|
||||||
|
bool RequestAddress();
|
||||||
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
|
};
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxPostIncrDecr
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
class FxPostIncrDecr : public FxExpression
|
||||||
|
{
|
||||||
|
int Token;
|
||||||
|
FxExpression *Base;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FxPostIncrDecr(FxExpression *base, int token);
|
||||||
|
~FxPostIncrDecr();
|
||||||
|
FxExpression *Resolve(FCompileContext&);
|
||||||
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
|
};
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// FxBinary
|
// FxBinary
|
||||||
|
@ -753,7 +792,7 @@ public:
|
||||||
FxClassMember(FxExpression*, PField*, const FScriptPosition&);
|
FxClassMember(FxExpression*, PField*, const FScriptPosition&);
|
||||||
~FxClassMember();
|
~FxClassMember();
|
||||||
FxExpression *Resolve(FCompileContext&);
|
FxExpression *Resolve(FCompileContext&);
|
||||||
void RequestAddress();
|
bool RequestAddress();
|
||||||
ExpEmit Emit(VMFunctionBuilder *build);
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -796,12 +835,13 @@ class FxArrayElement : public FxExpression
|
||||||
public:
|
public:
|
||||||
FxExpression *Array;
|
FxExpression *Array;
|
||||||
FxExpression *index;
|
FxExpression *index;
|
||||||
//bool AddressRequested;
|
bool AddressRequested;
|
||||||
|
bool AddressWritable;
|
||||||
|
|
||||||
FxArrayElement(FxExpression*, FxExpression*);
|
FxArrayElement(FxExpression*, FxExpression*);
|
||||||
~FxArrayElement();
|
~FxArrayElement();
|
||||||
FxExpression *Resolve(FCompileContext&);
|
FxExpression *Resolve(FCompileContext&);
|
||||||
//void RequestAddress();
|
bool RequestAddress();
|
||||||
ExpEmit Emit(VMFunctionBuilder *build);
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -218,13 +218,14 @@ FxExpression *FxExpression::Resolve(FCompileContext &ctx)
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
//
|
// Returns true if we can write to the address.
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
void FxExpression::RequestAddress()
|
bool FxExpression::RequestAddress()
|
||||||
{
|
{
|
||||||
ScriptPosition.Message(MSG_ERROR, "invalid dereference\n");
|
ScriptPosition.Message(MSG_ERROR, "invalid dereference\n");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -887,6 +888,166 @@ ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build)
|
||||||
return from;
|
return from;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxPreIncrDecr
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FxPreIncrDecr::FxPreIncrDecr(FxExpression *base, int token)
|
||||||
|
: FxExpression(base->ScriptPosition), Base(base), Token(token)
|
||||||
|
{
|
||||||
|
AddressRequested = false;
|
||||||
|
AddressWritable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FxPreIncrDecr::~FxPreIncrDecr()
|
||||||
|
{
|
||||||
|
SAFE_DELETE(Base);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FxPreIncrDecr::RequestAddress()
|
||||||
|
{
|
||||||
|
AddressRequested = true;
|
||||||
|
return AddressWritable;
|
||||||
|
}
|
||||||
|
|
||||||
|
FxExpression *FxPreIncrDecr::Resolve(FCompileContext &ctx)
|
||||||
|
{
|
||||||
|
CHECKRESOLVED();
|
||||||
|
SAFE_RESOLVE(Base, ctx);
|
||||||
|
|
||||||
|
ValueType = Base->ValueType;
|
||||||
|
|
||||||
|
if (!Base->IsNumeric())
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
else if (Base->ValueType == TypeBool)
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "%s is not allowed on type bool", FScanner::TokenName(Token).GetChars());
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (!(AddressWritable = Base->RequestAddress()))
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value");
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpEmit FxPreIncrDecr::Emit(VMFunctionBuilder *build)
|
||||||
|
{
|
||||||
|
assert(Token == TK_Incr || Token == TK_Decr);
|
||||||
|
assert(ValueType == Base->ValueType && IsNumeric());
|
||||||
|
|
||||||
|
int zero = build->GetConstantInt(0);
|
||||||
|
int regtype = ValueType->GetRegType();
|
||||||
|
ExpEmit pointer = Base->Emit(build);
|
||||||
|
|
||||||
|
ExpEmit value(build, regtype);
|
||||||
|
build->Emit(ValueType->GetLoadOp(), value.RegNum, pointer.RegNum, zero);
|
||||||
|
|
||||||
|
if (regtype == REGT_INT)
|
||||||
|
{
|
||||||
|
build->Emit((Token == TK_Incr) ? OP_ADD_RK : OP_SUB_RK, value.RegNum, value.RegNum, build->GetConstantInt(1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
build->Emit((Token == TK_Incr) ? OP_ADDF_RK : OP_SUBF_RK, value.RegNum, value.RegNum, build->GetConstantFloat(1.));
|
||||||
|
}
|
||||||
|
|
||||||
|
build->Emit(ValueType->GetStoreOp(), pointer.RegNum, value.RegNum, zero);
|
||||||
|
|
||||||
|
if (AddressRequested)
|
||||||
|
{
|
||||||
|
value.Free(build);
|
||||||
|
return pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer.Free(build);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxPostIncrDecr
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FxPostIncrDecr::FxPostIncrDecr(FxExpression *base, int token)
|
||||||
|
: FxExpression(base->ScriptPosition), Base(base), Token(token)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FxPostIncrDecr::~FxPostIncrDecr()
|
||||||
|
{
|
||||||
|
SAFE_DELETE(Base);
|
||||||
|
}
|
||||||
|
|
||||||
|
FxExpression *FxPostIncrDecr::Resolve(FCompileContext &ctx)
|
||||||
|
{
|
||||||
|
CHECKRESOLVED();
|
||||||
|
SAFE_RESOLVE(Base, ctx);
|
||||||
|
|
||||||
|
ValueType = Base->ValueType;
|
||||||
|
|
||||||
|
if (!Base->IsNumeric())
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
else if (Base->ValueType == TypeBool)
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "%s is not allowed on type bool", FScanner::TokenName(Token).GetChars());
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (!Base->RequestAddress())
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value");
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build)
|
||||||
|
{
|
||||||
|
assert(Token == TK_Incr || Token == TK_Decr);
|
||||||
|
assert(ValueType == Base->ValueType && IsNumeric());
|
||||||
|
|
||||||
|
int zero = build->GetConstantInt(0);
|
||||||
|
int regtype = ValueType->GetRegType();
|
||||||
|
ExpEmit pointer = Base->Emit(build);
|
||||||
|
|
||||||
|
ExpEmit out(build, regtype);
|
||||||
|
build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, zero);
|
||||||
|
|
||||||
|
ExpEmit assign(build, regtype);
|
||||||
|
if (regtype == REGT_INT)
|
||||||
|
{
|
||||||
|
build->Emit((Token == TK_Incr) ? OP_ADD_RK : OP_SUB_RK, assign.RegNum, out.RegNum, build->GetConstantInt(1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
build->Emit((Token == TK_Incr) ? OP_ADDF_RK : OP_SUBF_RK, assign.RegNum, out.RegNum, build->GetConstantFloat(1.));
|
||||||
|
}
|
||||||
|
|
||||||
|
build->Emit(ValueType->GetStoreOp(), pointer.RegNum, assign.RegNum, zero);
|
||||||
|
|
||||||
|
pointer.Free(build);
|
||||||
|
assign.Free(build);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
@ -2995,9 +3156,10 @@ FxClassMember::~FxClassMember()
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
void FxClassMember::RequestAddress()
|
bool FxClassMember::RequestAddress()
|
||||||
{
|
{
|
||||||
AddressRequested = true;
|
AddressRequested = true;
|
||||||
|
return !!(~membervar->Flags & VARF_ReadOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -3027,6 +3189,17 @@ ExpEmit FxClassMember::Emit(VMFunctionBuilder *build)
|
||||||
ExpEmit obj = classx->Emit(build);
|
ExpEmit obj = classx->Emit(build);
|
||||||
assert(obj.RegType == REGT_POINTER);
|
assert(obj.RegType == REGT_POINTER);
|
||||||
|
|
||||||
|
if (obj.Konst)
|
||||||
|
{
|
||||||
|
// If the situation where we are dereferencing a constant
|
||||||
|
// pointer is common, then it would probably be worthwhile
|
||||||
|
// to add new opcodes for those. But as of right now, I
|
||||||
|
// don't expect it to be a particularly common case.
|
||||||
|
ExpEmit newobj(build, REGT_POINTER);
|
||||||
|
build->Emit(OP_LKP, newobj.RegNum, obj.RegNum);
|
||||||
|
obj = newobj;
|
||||||
|
}
|
||||||
|
|
||||||
if (AddressRequested)
|
if (AddressRequested)
|
||||||
{
|
{
|
||||||
if (membervar->Offset == 0)
|
if (membervar->Offset == 0)
|
||||||
|
@ -3040,20 +3213,8 @@ ExpEmit FxClassMember::Emit(VMFunctionBuilder *build)
|
||||||
}
|
}
|
||||||
|
|
||||||
int offsetreg = build->GetConstantInt((int)membervar->Offset);
|
int offsetreg = build->GetConstantInt((int)membervar->Offset);
|
||||||
ExpEmit loc, tmp;
|
ExpEmit loc(build, membervar->Type->GetRegType());
|
||||||
|
|
||||||
if (obj.Konst)
|
|
||||||
{
|
|
||||||
// If the situation where we are dereferencing a constant
|
|
||||||
// pointer is common, then it would probably be worthwhile
|
|
||||||
// to add new opcodes for those. But as of right now, I
|
|
||||||
// don't expect it to be a particularly common case.
|
|
||||||
ExpEmit newobj(build, REGT_POINTER);
|
|
||||||
build->Emit(OP_LKP, newobj.RegNum, obj.RegNum);
|
|
||||||
obj = newobj;
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = ExpEmit(build, membervar->Type->GetRegType());
|
|
||||||
build->Emit(membervar->Type->GetLoadOp(), loc.RegNum, obj.RegNum, offsetreg);
|
build->Emit(membervar->Type->GetLoadOp(), loc.RegNum, obj.RegNum, offsetreg);
|
||||||
obj.Free(build);
|
obj.Free(build);
|
||||||
return loc;
|
return loc;
|
||||||
|
@ -3071,7 +3232,8 @@ FxArrayElement::FxArrayElement(FxExpression *base, FxExpression *_index)
|
||||||
{
|
{
|
||||||
Array=base;
|
Array=base;
|
||||||
index = _index;
|
index = _index;
|
||||||
//AddressRequested = false;
|
AddressRequested = false;
|
||||||
|
AddressWritable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -3092,12 +3254,11 @@ FxArrayElement::~FxArrayElement()
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
/*
|
bool FxArrayElement::RequestAddress()
|
||||||
void FxArrayElement::RequestAddress()
|
|
||||||
{
|
{
|
||||||
AddressRequested = true;
|
AddressRequested = true;
|
||||||
|
return AddressWritable;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
|
@ -3145,7 +3306,7 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
|
||||||
delete this;
|
delete this;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
Array->RequestAddress();
|
AddressWritable = Array->RequestAddress();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3159,13 +3320,13 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
|
||||||
{
|
{
|
||||||
ExpEmit start = Array->Emit(build);
|
ExpEmit start = Array->Emit(build);
|
||||||
PArray *const arraytype = static_cast<PArray*>(Array->ValueType);
|
PArray *const arraytype = static_cast<PArray*>(Array->ValueType);
|
||||||
PType *const elementtype = arraytype->ElementType;
|
ExpEmit dest(build, arraytype->ElementType->GetRegType());
|
||||||
ExpEmit dest(build, elementtype->GetRegType());
|
|
||||||
|
|
||||||
if (start.Konst)
|
if (start.Konst)
|
||||||
{
|
{
|
||||||
ExpEmit tmpstart(build, REGT_POINTER);
|
ExpEmit tmpstart(build, REGT_POINTER);
|
||||||
build->Emit(OP_LKP, tmpstart.RegNum, start.RegNum);
|
build->Emit(OP_LKP, tmpstart.RegNum, start.RegNum);
|
||||||
|
start.Free(build);
|
||||||
start = tmpstart;
|
start = tmpstart;
|
||||||
}
|
}
|
||||||
if (index->isConstant())
|
if (index->isConstant())
|
||||||
|
@ -3176,8 +3337,19 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
|
||||||
I_Error("Array index out of bounds");
|
I_Error("Array index out of bounds");
|
||||||
}
|
}
|
||||||
indexval *= arraytype->ElementSize;
|
indexval *= arraytype->ElementSize;
|
||||||
build->Emit(arraytype->ElementType->GetLoadOp(), dest.RegNum,
|
|
||||||
start.RegNum, build->GetConstantInt(indexval));
|
if (AddressRequested)
|
||||||
|
{
|
||||||
|
if (indexval != 0)
|
||||||
|
{
|
||||||
|
build->Emit(OP_ADDA_RK, start.RegNum, start.RegNum, build->GetConstantInt(indexval));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
build->Emit(arraytype->ElementType->GetLoadOp(), dest.RegNum,
|
||||||
|
start.RegNum, build->GetConstantInt(indexval));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3193,10 +3365,24 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
|
||||||
{
|
{
|
||||||
build->Emit(OP_SLL_RI, indexv.RegNum, indexv.RegNum, shiftbits);
|
build->Emit(OP_SLL_RI, indexv.RegNum, indexv.RegNum, shiftbits);
|
||||||
}
|
}
|
||||||
build->Emit(arraytype->ElementType->GetLoadOp() + 1, // added 1 to use the *_R version that
|
|
||||||
dest.RegNum, start.RegNum, indexv.RegNum); // takes the offset from a register
|
if (AddressRequested)
|
||||||
|
{
|
||||||
|
build->Emit(OP_ADDA_RR, start.RegNum, start.RegNum, indexv.RegNum);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
build->Emit(arraytype->ElementType->GetLoadOp() + 1, // added 1 to use the *_R version that
|
||||||
|
dest.RegNum, start.RegNum, indexv.RegNum); // takes the offset from a register
|
||||||
|
}
|
||||||
indexv.Free(build);
|
indexv.Free(build);
|
||||||
}
|
}
|
||||||
|
if (AddressRequested)
|
||||||
|
{
|
||||||
|
dest.Free(build);
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
start.Free(build);
|
start.Free(build);
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue