mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-10 14:51:51 +00:00
Added do-while loops to DECORATE
This commit is contained in:
parent
d1749233ec
commit
e2fa8c2257
3 changed files with 147 additions and 0 deletions
|
@ -946,6 +946,24 @@ public:
|
||||||
ExpEmit Emit(VMFunctionBuilder *build);
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxDoWhileLoop
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
class FxDoWhileLoop : public FxExpression
|
||||||
|
{
|
||||||
|
FxExpression *Condition;
|
||||||
|
FxExpression *Code;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FxDoWhileLoop(FxExpression *condition, FxExpression *code, const FScriptPosition &pos);
|
||||||
|
~FxDoWhileLoop();
|
||||||
|
FxExpression *Resolve(FCompileContext&);
|
||||||
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
|
};
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// FxJumpStatement
|
// FxJumpStatement
|
||||||
|
|
|
@ -3958,6 +3958,108 @@ ExpEmit FxWhileLoop::Emit(VMFunctionBuilder *build)
|
||||||
return ExpEmit();
|
return ExpEmit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxDoWhileLoop
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FxDoWhileLoop::FxDoWhileLoop(FxExpression *condition, FxExpression *code, const FScriptPosition &pos)
|
||||||
|
: FxExpression(pos), Condition(condition), Code(code)
|
||||||
|
{
|
||||||
|
ValueType = TypeVoid;
|
||||||
|
}
|
||||||
|
|
||||||
|
FxDoWhileLoop::~FxDoWhileLoop()
|
||||||
|
{
|
||||||
|
SAFE_DELETE(Condition);
|
||||||
|
SAFE_DELETE(Code);
|
||||||
|
}
|
||||||
|
|
||||||
|
FxExpression *FxDoWhileLoop::Resolve(FCompileContext &ctx)
|
||||||
|
{
|
||||||
|
CHECKRESOLVED();
|
||||||
|
SAFE_RESOLVE(Condition, ctx);
|
||||||
|
SAFE_RESOLVE_OPT(Code, ctx);
|
||||||
|
|
||||||
|
ctx.HandleJumps(TK_Break, this);
|
||||||
|
ctx.HandleJumps(TK_Continue, this);
|
||||||
|
|
||||||
|
if (Condition->ValueType != TypeBool)
|
||||||
|
{
|
||||||
|
Condition = new FxBoolCast(Condition);
|
||||||
|
SAFE_RESOLVE(Condition, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Condition->isConstant())
|
||||||
|
{
|
||||||
|
if (static_cast<FxConstant *>(Condition)->GetValue().GetBool() == false)
|
||||||
|
{ // The code executes once, if any.
|
||||||
|
if (JumpAddresses.Size() == 0)
|
||||||
|
{ // We would still have to handle the jumps however.
|
||||||
|
FxExpression *e = Code;
|
||||||
|
if (e == nullptr) e = new FxNop(ScriptPosition);
|
||||||
|
Code = nullptr;
|
||||||
|
delete this;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Code == nullptr)
|
||||||
|
{ // "do { } while (true);"
|
||||||
|
// Someone could be using this for testing.
|
||||||
|
ScriptPosition.Message(MSG_WARNING, "Infinite empty loop");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpEmit FxDoWhileLoop::Emit(VMFunctionBuilder *build)
|
||||||
|
{
|
||||||
|
assert(Condition->ValueType == TypeBool);
|
||||||
|
|
||||||
|
size_t loopstart, loopend;
|
||||||
|
size_t codestart;
|
||||||
|
|
||||||
|
// Execute the loop's content.
|
||||||
|
codestart = build->GetAddress();
|
||||||
|
if (Code != nullptr)
|
||||||
|
{
|
||||||
|
ExpEmit code = Code->Emit(build);
|
||||||
|
code.Free(build);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evaluate the condition and execute/break out of the loop.
|
||||||
|
loopstart = build->GetAddress();
|
||||||
|
if (!Condition->isConstant())
|
||||||
|
{
|
||||||
|
ExpEmit cond = Condition->Emit(build);
|
||||||
|
build->Emit(OP_TEST, cond.RegNum, 1);
|
||||||
|
cond.Free(build);
|
||||||
|
build->Backpatch(build->Emit(OP_JMP, 0), codestart);
|
||||||
|
}
|
||||||
|
else if (static_cast<FxConstant *>(Condition)->GetValue().GetBool() == true)
|
||||||
|
{ // Always looping
|
||||||
|
build->Backpatch(build->Emit(OP_JMP, 0), codestart);
|
||||||
|
}
|
||||||
|
loopend = build->GetAddress();
|
||||||
|
|
||||||
|
// Give a proper address to any break/continue statement within this loop.
|
||||||
|
for (unsigned int i = 0; i < JumpAddresses.Size(); i++)
|
||||||
|
{
|
||||||
|
if (JumpAddresses[i]->Token == TK_Break)
|
||||||
|
{
|
||||||
|
build->Backpatch(JumpAddresses[i]->Address, loopend);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // Continue statement.
|
||||||
|
build->Backpatch(JumpAddresses[i]->Address, loopstart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExpEmit();
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// FxJumpStatement
|
// FxJumpStatement
|
||||||
|
|
|
@ -501,6 +501,29 @@ static FxExpression *ParseWhile(FScanner &sc, FState state, FString statestring,
|
||||||
return new FxWhileLoop(cond, code, sc);
|
return new FxWhileLoop(cond, code, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FxExpression *ParseDoWhile(FScanner &sc, FState state, FString statestring, Baggage &bag,
|
||||||
|
PPrototype *&retproto, bool &lastwasret)
|
||||||
|
{
|
||||||
|
FxExpression *cond, *code;
|
||||||
|
PPrototype *proto;
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
sc.MustGetStringName("{"); // Enforce braces like for if statements.
|
||||||
|
code = ParseActions(sc, state, statestring, bag, proto, ret);
|
||||||
|
|
||||||
|
sc.MustGetStringName("while");
|
||||||
|
sc.MustGetStringName("(");
|
||||||
|
cond = ParseExpression(sc, bag.Info);
|
||||||
|
sc.MustGetStringName(")");
|
||||||
|
sc.MustGetStringName(";");
|
||||||
|
sc.MustGetString();
|
||||||
|
|
||||||
|
retproto = ReturnCheck(retproto, proto, sc);
|
||||||
|
lastwasret = false;
|
||||||
|
|
||||||
|
return new FxDoWhileLoop(cond, code, sc);
|
||||||
|
}
|
||||||
|
|
||||||
FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag,
|
FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag,
|
||||||
PPrototype *&retproto, bool &endswithret)
|
PPrototype *&retproto, bool &endswithret)
|
||||||
{
|
{
|
||||||
|
@ -533,6 +556,10 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg
|
||||||
{ // Handle a while loop
|
{ // Handle a while loop
|
||||||
add = ParseWhile(sc, state, statestring, bag, proto, lastwasret);
|
add = ParseWhile(sc, state, statestring, bag, proto, lastwasret);
|
||||||
}
|
}
|
||||||
|
else if (sc.Compare("do"))
|
||||||
|
{ // Handle a do-while loop
|
||||||
|
add = ParseDoWhile(sc, state, statestring, bag, proto, lastwasret);
|
||||||
|
}
|
||||||
else if (sc.Compare("return"))
|
else if (sc.Compare("return"))
|
||||||
{ // Handle a return statement
|
{ // Handle a return statement
|
||||||
lastwasret = true;
|
lastwasret = true;
|
||||||
|
|
Loading…
Reference in a new issue