Added do-while loops to DECORATE

This commit is contained in:
Leonard2 2016-07-27 17:14:54 +02:00 committed by Christoph Oelckers
parent d1749233ec
commit e2fa8c2257
3 changed files with 147 additions and 0 deletions

View File

@ -946,6 +946,24 @@ public:
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

View File

@ -3958,6 +3958,108 @@ ExpEmit FxWhileLoop::Emit(VMFunctionBuilder *build)
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

View File

@ -501,6 +501,29 @@ static FxExpression *ParseWhile(FScanner &sc, FState state, FString statestring,
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,
PPrototype *&retproto, bool &endswithret)
{
@ -533,6 +556,10 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg
{ // Handle a while loop
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"))
{ // Handle a return statement
lastwasret = true;