From c4eafc1c38c9da6502a3971c2e379821673d3bc8 Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Tue, 26 Jul 2016 23:57:26 +0200 Subject: [PATCH] DECORATE can now handle jump statements break and continue were added but are not yet useable anywhere This was made general enough so that loops and switch statements that accept breaks/continues can be done without much difficulty as well as goto statements with explicit labels if those are ever wanted --- src/thingdef/thingdef_exp.h | 41 +++++++++---- src/thingdef/thingdef_expression.cpp | 90 +++++++++++++++++++++++++--- src/thingdef/thingdef_states.cpp | 12 ++++ 3 files changed, 121 insertions(+), 22 deletions(-) diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 58820ea153..3353cad468 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -50,6 +50,7 @@ #define SAFE_RESOLVE(p,c) RESOLVE(p,c); ABORT(p) class VMFunctionBuilder; +class FxJumpStatement; //========================================================================== // @@ -59,21 +60,15 @@ class VMFunctionBuilder; struct FCompileContext { - PClassActor *cls; + TArray Jumps; + PClassActor *Class; - FCompileContext(PClassActor *_cls = NULL) - { - cls = _cls; - } + FCompileContext(PClassActor *cls = nullptr); - PSymbol *FindInClass(FName identifier) - { - return cls ? cls->Symbols.FindSymbol(identifier, true) : NULL; - } - PSymbol *FindGlobal(FName identifier) - { - return GlobalSymbols.FindSymbol(identifier, true); - } + PSymbol *FindInClass(FName identifier); + PSymbol *FindGlobal(FName identifier); + + void HandleJumps(int token, FxExpression *handler); }; //========================================================================== @@ -212,6 +207,8 @@ public: virtual ExpEmit Emit(VMFunctionBuilder *build); + TArray JumpAddresses; + FScriptPosition ScriptPosition; PType *ValueType; @@ -930,6 +927,24 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxJumpStatement +// +//========================================================================== + +class FxJumpStatement : public FxExpression +{ +public: + FxJumpStatement(int token, const FScriptPosition &pos); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); + + int Token; + size_t Address; + FxExpression *AddressResolver; +}; + //========================================================================== // // FxReturnStatement diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index b4a0b3fda1..4e13b7bebc 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -85,6 +85,45 @@ static const FLOP FxFlops[] = { NAME_TanH, FLOP_TANH, [](double v) { return g_tanh(v); } }, }; +//========================================================================== +// +// FCompileContext +// +//========================================================================== + +FCompileContext::FCompileContext(PClassActor *cls) : Class(cls) +{ +} + +PSymbol *FCompileContext::FindInClass(FName identifier) +{ + return Class ? Class->Symbols.FindSymbol(identifier, true) : nullptr; +} +PSymbol *FCompileContext::FindGlobal(FName identifier) +{ + return GlobalSymbols.FindSymbol(identifier, true); +} + +void FCompileContext::HandleJumps(int token, FxExpression *handler) +{ + for (unsigned int i = 0; i < Jumps.Size(); i++) + { + if (Jumps[i]->Token == token) + { + Jumps[i]->AddressResolver = handler; + handler->JumpAddresses.Push(Jumps[i]); + Jumps.Delete(i); + i--; + } + } +} + +//========================================================================== +// +// ExpEmit +// +//========================================================================== + ExpEmit::ExpEmit(VMFunctionBuilder *build, int type) : RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false), Fixed(false) { @@ -2838,14 +2877,14 @@ FxSelf::FxSelf(const FScriptPosition &pos) FxExpression *FxSelf::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); - if (!ctx.cls) + if (!ctx.Class) { // can't really happen with DECORATE's expression evaluator. ScriptPosition.Message(MSG_ERROR, "self used outside of a member function"); delete this; return NULL; } - ValueType = ctx.cls; + ValueType = ctx.Class; ValueType = NewPointer(RUNTIME_CLASS(DObject)); return this; } @@ -3818,6 +3857,39 @@ ExpEmit FxIfStatement::Emit(VMFunctionBuilder *build) return ExpEmit(); } +//========================================================================== +// +// FxJumpStatement +// +//========================================================================== + +FxJumpStatement::FxJumpStatement(int token, const FScriptPosition &pos) +: FxExpression(pos), Token(token), AddressResolver(nullptr) +{ + ValueType = TypeVoid; +} + +FxExpression *FxJumpStatement::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + + ctx.Jumps.Push(this); + + return this; +} + +ExpEmit FxJumpStatement::Emit(VMFunctionBuilder *build) +{ + if (AddressResolver == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Jump statement %s has nowhere to go!", FScanner::TokenName(Token)); + } + + Address = build->Emit(OP_JMP, 0); + + return ExpEmit(); +} + //========================================================================== // //========================================================================== @@ -4008,19 +4080,19 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build) FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); - if (ctx.cls->NumOwnedStates == 0) + if (ctx.Class->NumOwnedStates == 0) { // This can't really happen assert(false); } - if (ctx.cls->NumOwnedStates <= index) + if (ctx.Class->NumOwnedStates <= index) { ScriptPosition.Message(MSG_ERROR, "%s: Attempt to jump to non existing state index %d", - ctx.cls->TypeName.GetChars(), index); + ctx.Class->TypeName.GetChars(), index); delete this; return NULL; } - FxExpression *x = new FxConstant(ctx.cls->OwnedStates + index, ScriptPosition); + FxExpression *x = new FxConstant(ctx.Class->OwnedStates + index, ScriptPosition); delete this; return x; } @@ -4068,7 +4140,7 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) } else if (names[0] == NAME_Super) { - scope = dyn_cast(ctx.cls->ParentClass); + scope = dyn_cast(ctx.Class->ParentClass); } else { @@ -4079,9 +4151,9 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) delete this; return NULL; } - else if (!scope->IsDescendantOf(ctx.cls)) + else if (!scope->IsDescendantOf(ctx.Class)) { - ScriptPosition.Message(MSG_ERROR, "'%s' is not an ancestor of '%s'", names[0].GetChars(),ctx.cls->TypeName.GetChars()); + ScriptPosition.Message(MSG_ERROR, "'%s' is not an ancestor of '%s'", names[0].GetChars(),ctx.Class->TypeName.GetChars()); delete this; return NULL; } diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index ae18051190..4642217145 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -529,6 +529,18 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg sc.MustGetString(); add = new FxReturnStatement(retexp, sc); } + else if (sc.Compare("break")) + { + add = new FxJumpStatement(TK_Break, sc); + sc.MustGetStringName(";"); + sc.MustGetString(); + } + else if (sc.Compare("continue")) + { + add = new FxJumpStatement(TK_Continue, sc); + sc.MustGetStringName(";"); + sc.MustGetString(); + } else { // Handle a regular action function call add = ParseAction(sc, state, statestring, bag);