mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-22 20:21:26 +00:00
Added for loops to DECORATE
This commit is contained in:
parent
e2fa8c2257
commit
d0b953cbb7
3 changed files with 194 additions and 0 deletions
|
@ -964,6 +964,26 @@ public:
|
|||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxForLoop
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FxForLoop : public FxExpression
|
||||
{
|
||||
FxExpression *Init;
|
||||
FxExpression *Condition;
|
||||
FxExpression *Iteration;
|
||||
FxExpression *Code;
|
||||
|
||||
public:
|
||||
FxForLoop(FxExpression *init, FxExpression *condition, FxExpression *iteration, FxExpression *code, const FScriptPosition &pos);
|
||||
~FxForLoop();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxJumpStatement
|
||||
|
|
|
@ -4060,6 +4060,133 @@ ExpEmit FxDoWhileLoop::Emit(VMFunctionBuilder *build)
|
|||
return ExpEmit();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxForLoop
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxForLoop::FxForLoop(FxExpression *init, FxExpression *condition, FxExpression *iteration, FxExpression *code, const FScriptPosition &pos)
|
||||
: FxExpression(pos), Init(init), Condition(condition), Iteration(iteration), Code(code)
|
||||
{
|
||||
ValueType = TypeVoid;
|
||||
}
|
||||
|
||||
FxForLoop::~FxForLoop()
|
||||
{
|
||||
SAFE_DELETE(Init);
|
||||
SAFE_DELETE(Condition);
|
||||
SAFE_DELETE(Iteration);
|
||||
SAFE_DELETE(Code);
|
||||
}
|
||||
|
||||
FxExpression *FxForLoop::Resolve(FCompileContext &ctx)
|
||||
{
|
||||
CHECKRESOLVED();
|
||||
SAFE_RESOLVE_OPT(Init, ctx);
|
||||
SAFE_RESOLVE_OPT(Condition, ctx);
|
||||
SAFE_RESOLVE_OPT(Iteration, ctx);
|
||||
SAFE_RESOLVE_OPT(Code, ctx);
|
||||
|
||||
ctx.HandleJumps(TK_Break, this);
|
||||
ctx.HandleJumps(TK_Continue, this);
|
||||
|
||||
if (Condition != nullptr)
|
||||
{
|
||||
if (Condition->ValueType != TypeBool)
|
||||
{
|
||||
Condition = new FxBoolCast(Condition);
|
||||
SAFE_RESOLVE(Condition, ctx);
|
||||
}
|
||||
|
||||
if (Condition->isConstant())
|
||||
{
|
||||
if (static_cast<FxConstant *>(Condition)->GetValue().GetBool() == false)
|
||||
{ // Nothing happens
|
||||
FxExpression *nop = new FxNop(ScriptPosition);
|
||||
delete this;
|
||||
return nop;
|
||||
}
|
||||
else
|
||||
{ // "for (..; true; ..)"
|
||||
delete Condition;
|
||||
Condition = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Condition == nullptr && Code == nullptr)
|
||||
{ // "for (..; ; ..) { }"
|
||||
// Someone could be using this for testing.
|
||||
ScriptPosition.Message(MSG_WARNING, "Infinite empty loop");
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
ExpEmit FxForLoop::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
assert((Condition && Condition->ValueType == TypeBool && !Condition->isConstant()) || Condition == nullptr);
|
||||
|
||||
size_t loopstart, loopend;
|
||||
size_t codestart;
|
||||
size_t jumpspot;
|
||||
|
||||
// Init statement.
|
||||
if (Init != nullptr)
|
||||
{
|
||||
ExpEmit init = Init->Emit(build);
|
||||
init.Free(build);
|
||||
}
|
||||
|
||||
// Evaluate the condition and execute/break out of the loop.
|
||||
codestart = build->GetAddress();
|
||||
if (Condition != nullptr)
|
||||
{
|
||||
ExpEmit cond = Condition->Emit(build);
|
||||
build->Emit(OP_TEST, cond.RegNum, 0);
|
||||
cond.Free(build);
|
||||
jumpspot = build->Emit(OP_JMP, 0);
|
||||
}
|
||||
|
||||
// Execute the loop's content.
|
||||
if (Code != nullptr)
|
||||
{
|
||||
ExpEmit code = Code->Emit(build);
|
||||
code.Free(build);
|
||||
}
|
||||
|
||||
// Iteration statement.
|
||||
loopstart = build->GetAddress();
|
||||
if (Iteration != nullptr)
|
||||
{
|
||||
ExpEmit iter = Iteration->Emit(build);
|
||||
iter.Free(build);
|
||||
}
|
||||
build->Backpatch(build->Emit(OP_JMP, 0), codestart);
|
||||
|
||||
// End of loop.
|
||||
loopend = build->GetAddress();
|
||||
if (Condition != nullptr)
|
||||
{
|
||||
build->Backpatch(jumpspot, loopend);
|
||||
}
|
||||
|
||||
// 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
|
||||
|
|
|
@ -524,6 +524,49 @@ static FxExpression *ParseDoWhile(FScanner &sc, FState state, FString statestrin
|
|||
return new FxDoWhileLoop(cond, code, sc);
|
||||
}
|
||||
|
||||
static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, Baggage &bag,
|
||||
PPrototype *&retproto, bool &lastwasret)
|
||||
{
|
||||
FxExpression *init = nullptr;
|
||||
FxExpression *cond = nullptr;
|
||||
FxExpression *iter = nullptr;
|
||||
FxExpression *code = nullptr;
|
||||
PPrototype *proto;
|
||||
bool ret;
|
||||
|
||||
// Parse the statements.
|
||||
sc.MustGetStringName("(");
|
||||
sc.MustGetString();
|
||||
if (!sc.Compare(";"))
|
||||
{
|
||||
init = ParseAction(sc, state, statestring, bag); // That's all DECORATE can handle for now.
|
||||
sc.MustGetStringName(";");
|
||||
}
|
||||
sc.MustGetString();
|
||||
if (!sc.Compare(";"))
|
||||
{
|
||||
sc.UnGet();
|
||||
cond = ParseExpression(sc, bag.Info);
|
||||
sc.MustGetStringName(";");
|
||||
}
|
||||
sc.MustGetString();
|
||||
if (!sc.Compare(")"))
|
||||
{
|
||||
iter = ParseAction(sc, state, statestring, bag);
|
||||
sc.MustGetStringName(")");
|
||||
}
|
||||
|
||||
// Now parse the loop's content.
|
||||
sc.MustGetStringName("{"); // Enforce braces like for if statements.
|
||||
code = ParseActions(sc, state, statestring, bag, proto, ret);
|
||||
sc.MustGetString();
|
||||
|
||||
retproto = ReturnCheck(retproto, proto, sc);
|
||||
lastwasret = false;
|
||||
|
||||
return new FxForLoop(init, cond, iter, code, sc);
|
||||
}
|
||||
|
||||
FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag,
|
||||
PPrototype *&retproto, bool &endswithret)
|
||||
{
|
||||
|
@ -560,6 +603,10 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg
|
|||
{ // Handle a do-while loop
|
||||
add = ParseDoWhile(sc, state, statestring, bag, proto, lastwasret);
|
||||
}
|
||||
else if (sc.Compare("for"))
|
||||
{ // Handle a for loop
|
||||
add = ParseFor(sc, state, statestring, bag, proto, lastwasret);
|
||||
}
|
||||
else if (sc.Compare("return"))
|
||||
{ // Handle a return statement
|
||||
lastwasret = true;
|
||||
|
|
Loading…
Reference in a new issue