mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-28 15:02:01 +00:00
Merge branch 'master' of https://github.com/rheit/zdoom
This commit is contained in:
commit
9a5cbbe6d8
18 changed files with 1077 additions and 315 deletions
|
@ -509,9 +509,11 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
|||
set( CMAKE_C_FLAGS "-Wno-unused-result ${CMAKE_C_FLAGS}" )
|
||||
set( CMAKE_CXX_FLAGS "-Wno-unused-result ${CMAKE_CXX_FLAGS}" )
|
||||
endif()
|
||||
if(APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
if( CMAKE_CXX_COMPILER_ID STREQUAL "Clang" )
|
||||
if( APPLE OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "3.6" )
|
||||
set( CMAKE_CXX_FLAGS "-Wno-inconsistent-missing-override ${CMAKE_CXX_FLAGS}" )
|
||||
endif()
|
||||
endif()
|
||||
set( CMAKE_C_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers -ffp-contract=off ${CMAKE_C_FLAGS}" )
|
||||
set( CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers -ffp-contract=off ${CMAKE_CXX_FLAGS}" )
|
||||
|
||||
|
|
|
@ -147,6 +147,7 @@ static FCompatOption Options[] =
|
|||
{ "soundcutoff", COMPATF2_SOUNDCUTOFF, SLOT_COMPAT2 },
|
||||
{ "pointonline", COMPATF2_POINTONLINE, SLOT_COMPAT2 },
|
||||
{ "multiexit", COMPATF2_MULTIEXIT, SLOT_COMPAT2 },
|
||||
{ "teleport", COMPATF2_TELEPORT, SLOT_COMPAT2 },
|
||||
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
|
|
|
@ -574,7 +574,7 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL)
|
|||
|
||||
case 4: // Old ZDoom compat mode
|
||||
v = COMPATF_SOUNDTARGET | COMPATF_LIGHT;
|
||||
w = COMPATF2_MULTIEXIT;
|
||||
w = COMPATF2_MULTIEXIT | COMPATF2_TELEPORT;
|
||||
break;
|
||||
|
||||
case 5: // MBF compat mode
|
||||
|
@ -630,6 +630,7 @@ CVAR (Flag, compat_floormove, compatflags2, COMPATF2_FLOORMOVE);
|
|||
CVAR (Flag, compat_soundcutoff, compatflags2, COMPATF2_SOUNDCUTOFF);
|
||||
CVAR (Flag, compat_pointonline, compatflags2, COMPATF2_POINTONLINE);
|
||||
CVAR (Flag, compat_multiexit, compatflags2, COMPATF2_MULTIEXIT);
|
||||
CVAR (Flag, compat_teleport, compatflags2, COMPATF2_TELEPORT);
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
|
|
@ -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_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_ReadOnly (1<<4) // field is read only, do not write to it
|
||||
|
||||
// Symbol information -------------------------------------------------------
|
||||
|
||||
|
|
|
@ -342,6 +342,7 @@ enum : unsigned int
|
|||
COMPATF2_SOUNDCUTOFF = 1 << 2, // Cut off sounds when an actor vanishes instead of making it owner-less
|
||||
COMPATF2_POINTONLINE = 1 << 3, // Use original but buggy P_PointOnLineSide() and P_PointOnDivlineSideCompat()
|
||||
COMPATF2_MULTIEXIT = 1 << 4, // Level exit can be triggered multiple times (required by Daedalus's travel tubes, thanks to a faulty script)
|
||||
COMPATF2_TELEPORT = 1 << 5, // Don't let indirect teleports trigger sector actions
|
||||
};
|
||||
|
||||
// Emulate old bugs for select maps. These are not exposed by a cvar
|
||||
|
|
|
@ -1341,6 +1341,7 @@ MapFlagHandlers[] =
|
|||
{ "compat_soundcutoff", MITYPE_COMPATFLAG, 0, COMPATF2_SOUNDCUTOFF },
|
||||
{ "compat_pointonline", MITYPE_COMPATFLAG, 0, COMPATF2_POINTONLINE },
|
||||
{ "compat_multiexit", MITYPE_COMPATFLAG, 0, COMPATF2_MULTIEXIT },
|
||||
{ "compat_teleport", MITYPE_COMPATFLAG, 0, COMPATF2_TELEPORT },
|
||||
{ "cd_start_track", MITYPE_EATNEXT, 0, 0 },
|
||||
{ "cd_end1_track", MITYPE_EATNEXT, 0, 0 },
|
||||
{ "cd_end2_track", MITYPE_EATNEXT, 0, 0 },
|
||||
|
|
|
@ -891,16 +891,16 @@ static void DrawCoordinates(player_t * CPlayer)
|
|||
default:
|
||||
case 0:
|
||||
vwidth = SCREENWIDTH;
|
||||
vheight = SCREENWIDTH;
|
||||
vheight = SCREENHEIGHT;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
vwidth = SCREENWIDTH/2;
|
||||
vheight = SCREENWIDTH/2;
|
||||
vheight = SCREENHEIGHT/2;
|
||||
break;
|
||||
case 3:
|
||||
vwidth = SCREENWIDTH/4;
|
||||
vheight = SCREENWIDTH/4;
|
||||
vheight = SCREENHEIGHT/4;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -654,6 +654,7 @@ xx(DecoCallLineSpecial)
|
|||
xx(DecoNameToClass)
|
||||
xx(DecoFindMultiNameState)
|
||||
xx(DecoFindSingleNameState)
|
||||
xx(DecoHandleRuntimeState)
|
||||
xx(Damage)
|
||||
|
||||
// basic type names
|
||||
|
|
|
@ -434,7 +434,8 @@ bool P_TeleportMove(AActor* thing, const DVector3 &pos, bool telefrag, bool modi
|
|||
|
||||
// If this teleport was caused by a move, P_TryMove() will handle the
|
||||
// sector transition messages better than we can here.
|
||||
if (!(thing->flags6 & MF6_INTRYMOVE))
|
||||
// This needs to be compatibility optioned because some older maps exploited this missing feature.
|
||||
if (!(thing->flags6 & MF6_INTRYMOVE) && !(i_compatflags2 & COMPATF2_TELEPORT))
|
||||
{
|
||||
thing->CheckSectorTransition(oldsec);
|
||||
}
|
||||
|
|
|
@ -270,23 +270,28 @@ static void FinishThingdef()
|
|||
for (i = 0; i < StateTempCalls.Size(); ++i)
|
||||
{
|
||||
FStateTempCall *tcall = StateTempCalls[i];
|
||||
VMFunction *func;
|
||||
VMFunction *func = nullptr;
|
||||
|
||||
assert(tcall->Code != NULL);
|
||||
|
||||
// We don't know the return type in advance for anonymous functions.
|
||||
FCompileContext ctx(tcall->ActorClass, nullptr);
|
||||
tcall->Code = tcall->Code->Resolve(ctx);
|
||||
tcall->Proto = ctx.ReturnProto;
|
||||
|
||||
// Make sure resolving it didn't obliterate it.
|
||||
if (tcall->Code != nullptr)
|
||||
{
|
||||
// Can we call this function directly without wrapping it in an
|
||||
// anonymous function? e.g. Are we passing any parameters to it?
|
||||
func = tcall->Code->GetDirectFunction();
|
||||
if (func == NULL)
|
||||
{
|
||||
FCompileContext ctx(tcall->ActorClass);
|
||||
tcall->Code = tcall->Code->Resolve(ctx);
|
||||
|
||||
// Make sure resolving it didn't obliterate it.
|
||||
if (tcall->Code != NULL)
|
||||
if (func == nullptr)
|
||||
{
|
||||
VMFunctionBuilder buildit;
|
||||
|
||||
assert(tcall->Proto != nullptr);
|
||||
|
||||
// Allocate registers used to pass parameters in.
|
||||
// self, stateowner, state (all are pointers)
|
||||
buildit.Registers[REGT_POINTER].Get(3);
|
||||
|
@ -300,15 +305,7 @@ static void FinishThingdef()
|
|||
// Generate prototype for this anonymous function
|
||||
TArray<PType *> args(3);
|
||||
SetImplicitArgs(&args, NULL, tcall->ActorClass, VARF_Method | VARF_Action);
|
||||
if (tcall->Proto != NULL)
|
||||
{
|
||||
sfunc->Proto = NewPrototype(tcall->Proto->ReturnTypes, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
TArray<PType *> norets(0);
|
||||
sfunc->Proto = NewPrototype(norets, args);
|
||||
}
|
||||
|
||||
func = sfunc;
|
||||
|
||||
|
@ -321,11 +318,9 @@ static void FinishThingdef()
|
|||
codesize += sfunc->CodeSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tcall->Code != NULL)
|
||||
{
|
||||
|
||||
delete tcall->Code;
|
||||
tcall->Code = NULL;
|
||||
tcall->Code = nullptr;
|
||||
for (int k = 0; k < tcall->NumStates; ++k)
|
||||
{
|
||||
tcall->ActorClass->OwnedStates[tcall->FirstState + k].SetAction(func);
|
||||
|
|
|
@ -190,10 +190,9 @@ AFuncDesc *FindFunction(const char * string);
|
|||
void ParseStates(FScanner &sc, PClassActor *actor, AActor *defaults, Baggage &bag);
|
||||
void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray<FxExpression *> &out_params,
|
||||
PFunction *afd, FString statestring, FStateDefinitions *statedef);
|
||||
FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag, PPrototype *&proto, bool &endswithret);
|
||||
FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &endswithret);
|
||||
class FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, Baggage &bag);
|
||||
FName CheckCastKludges(FName in);
|
||||
void AddImplicitReturn(class FxSequence *code, const PPrototype *proto, FScanner &sc);
|
||||
void SetImplicitArgs(TArray<PType *> *args, TArray<DWORD> *argflags, PClassActor *cls, DWORD funcflags);
|
||||
|
||||
PFunction *FindGlobalActionFunction(const char *name);
|
||||
|
@ -356,6 +355,7 @@ int MatchString (const char *in, const char **strings);
|
|||
|
||||
|
||||
#define ACTION_RETURN_STATE(v) do { FState *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_STATE); return 1; } return 0; } while(0)
|
||||
#define ACTION_RETURN_FLOAT(v) do { double u = v; if (numret > 0) { assert(ret != nullptr); ret->SetFloat(u); return 1; } return 0; } while(0)
|
||||
#define ACTION_RETURN_INT(v) do { int u = v; if (numret > 0) { assert(ret != NULL); ret->SetInt(u); return 1; } return 0; } while(0)
|
||||
#define ACTION_RETURN_BOOL(v) ACTION_RETURN_INT(v)
|
||||
|
||||
|
|
|
@ -634,35 +634,35 @@ void InitThingdef()
|
|||
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_Args, array5, VARF_Native, myoffsetof(AActor, args)));
|
||||
symt.AddSymbol(new PField(NAME_CeilingZ, TypeFloat64, VARF_Native, myoffsetof(AActor,ceilingz)));
|
||||
symt.AddSymbol(new PField(NAME_FloorZ, TypeFloat64, VARF_Native, myoffsetof(AActor,floorz)));
|
||||
symt.AddSymbol(new PField(NAME_Health, TypeSInt32, VARF_Native, myoffsetof(AActor,health)));
|
||||
symt.AddSymbol(new PField(NAME_CeilingZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, ceilingz)));
|
||||
symt.AddSymbol(new PField(NAME_FloorZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, floorz)));
|
||||
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_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_Special, TypeSInt32, VARF_Native, myoffsetof(AActor, special)));
|
||||
symt.AddSymbol(new PField(NAME_TID, TypeSInt32, VARF_Native, myoffsetof(AActor,tid)));
|
||||
symt.AddSymbol(new PField(NAME_TIDtoHate, TypeSInt32, VARF_Native, myoffsetof(AActor,TIDtoHate)));
|
||||
symt.AddSymbol(new PField(NAME_WaterLevel, TypeSInt32, VARF_Native, 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_Y, TypeFloat64, VARF_Native, 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_VelX, TypeFloat64, VARF_Native, myoffsetof(AActor,Vel.X)));
|
||||
symt.AddSymbol(new PField(NAME_VelY, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Y)));
|
||||
symt.AddSymbol(new PField(NAME_VelZ, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Z)));
|
||||
symt.AddSymbol(new PField(NAME_MomX, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.X)));
|
||||
symt.AddSymbol(new PField(NAME_MomY, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Y)));
|
||||
symt.AddSymbol(new PField(NAME_MomZ, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Z)));
|
||||
symt.AddSymbol(new PField(NAME_TID, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, tid)));
|
||||
symt.AddSymbol(new PField(NAME_TIDtoHate, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, TIDtoHate)));
|
||||
symt.AddSymbol(new PField(NAME_WaterLevel, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, waterlevel)));
|
||||
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|VARF_ReadOnly, myoffsetof(AActor, __Pos.Y))); // 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|VARF_ReadOnly, myoffsetof(AActor, Vel.X)));
|
||||
symt.AddSymbol(new PField(NAME_VelY, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Y)));
|
||||
symt.AddSymbol(new PField(NAME_VelZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Z)));
|
||||
symt.AddSymbol(new PField(NAME_MomX, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.X)));
|
||||
symt.AddSymbol(new PField(NAME_MomY, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Y)));
|
||||
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_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_Accuracy, TypeSInt32, VARF_Native, myoffsetof(AActor, accuracy)));
|
||||
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_Radius, TypeFloat64, VARF_Native, myoffsetof(AActor,radius)));
|
||||
symt.AddSymbol(new PField(NAME_Height, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Height)));
|
||||
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_MeleeRange, TypeFloat64, VARF_Native, myoffsetof(AActor, meleerange)));
|
||||
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_DefThreshold,TypeSInt32, VARF_Native, myoffsetof(AActor,DefThreshold)));
|
||||
symt.AddSymbol(new PField(NAME_Threshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, threshold)));
|
||||
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
|
||||
// [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);
|
||||
|
@ -95,18 +96,83 @@ FxExpression *ParseExpression (FScanner &sc, PClassActor *cls, bool mustresolve)
|
|||
|
||||
static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls)
|
||||
{
|
||||
FxExpression *condition = ParseExpressionL (sc, cls);
|
||||
FxExpression *base = ParseExpressionL (sc, cls);
|
||||
|
||||
if (sc.CheckToken('?'))
|
||||
{
|
||||
FxExpression *truex = ParseExpressionM (sc, cls);
|
||||
sc.MustGetToken(':');
|
||||
FxExpression *falsex = ParseExpressionM (sc, cls);
|
||||
return new FxConditional(condition, truex, falsex);
|
||||
return new FxConditional(base, truex, falsex);
|
||||
}
|
||||
else if (sc.CheckToken('='))
|
||||
{
|
||||
FxExpression *right = ParseExpressionM(sc, cls);
|
||||
return new FxAssign(base, right);
|
||||
}
|
||||
else
|
||||
{
|
||||
return condition;
|
||||
FxBinary *exp;
|
||||
FxAssignSelf *left = new FxAssignSelf(sc);
|
||||
|
||||
sc.GetToken();
|
||||
switch (sc.TokenType)
|
||||
{
|
||||
case TK_AddEq:
|
||||
exp = new FxAddSub('+', left, nullptr);
|
||||
break;
|
||||
|
||||
case TK_SubEq:
|
||||
exp = new FxAddSub('-', left, nullptr);
|
||||
break;
|
||||
|
||||
case TK_MulEq:
|
||||
exp = new FxMulDiv('*', left, nullptr);
|
||||
break;
|
||||
|
||||
case TK_DivEq:
|
||||
exp = new FxMulDiv('/', left, nullptr);
|
||||
break;
|
||||
|
||||
case TK_ModEq:
|
||||
exp = new FxMulDiv('%', left, nullptr);
|
||||
break;
|
||||
|
||||
case TK_LShiftEq:
|
||||
exp = new FxBinaryInt(TK_LShift, left, nullptr);
|
||||
break;
|
||||
|
||||
case TK_RShiftEq:
|
||||
exp = new FxBinaryInt(TK_RShift, left, nullptr);
|
||||
break;
|
||||
|
||||
case TK_URShiftEq:
|
||||
exp = new FxBinaryInt(TK_URShift, left, nullptr);
|
||||
break;
|
||||
|
||||
case TK_AndEq:
|
||||
exp = new FxBinaryInt('&', left, nullptr);
|
||||
break;
|
||||
|
||||
case TK_XorEq:
|
||||
exp = new FxBinaryInt('^', left, nullptr);
|
||||
break;
|
||||
|
||||
case TK_OrEq:
|
||||
exp = new FxBinaryInt('|', left, nullptr);
|
||||
break;
|
||||
|
||||
default:
|
||||
sc.UnGet();
|
||||
delete left;
|
||||
return base;
|
||||
}
|
||||
|
||||
exp->right = ParseExpressionM(sc, cls);
|
||||
|
||||
FxAssign *ret = new FxAssign(base, exp);
|
||||
left->Assignment = ret;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -257,6 +323,10 @@ static FxExpression *ParseExpressionB (FScanner &sc, PClassActor *cls)
|
|||
case '+':
|
||||
return new FxPlusSign(ParseExpressionA (sc, cls));
|
||||
|
||||
case TK_Incr:
|
||||
case TK_Decr:
|
||||
return new FxPreIncrDecr(ParseExpressionA(sc, cls), sc.TokenType);
|
||||
|
||||
default:
|
||||
sc.UnGet();
|
||||
return ParseExpressionA (sc, cls);
|
||||
|
@ -312,6 +382,14 @@ static FxExpression *ParseExpressionA (FScanner &sc, PClassActor *cls)
|
|||
sc.MustGetToken(']');
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -357,6 +435,49 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
|
|||
// a cheap way to get them working when people use "name" instead of 'name'.
|
||||
return new FxConstant(FName(sc.String), scpos);
|
||||
}
|
||||
else if (sc.CheckToken(TK_Bool))
|
||||
{
|
||||
sc.MustGetToken('(');
|
||||
FxExpression *exp = ParseExpressionM(sc, cls);
|
||||
sc.MustGetToken(')');
|
||||
return new FxBoolCast(exp);
|
||||
}
|
||||
else if (sc.CheckToken(TK_Int))
|
||||
{
|
||||
sc.MustGetToken('(');
|
||||
FxExpression *exp = ParseExpressionM(sc, cls);
|
||||
sc.MustGetToken(')');
|
||||
return new FxIntCast(exp);
|
||||
}
|
||||
else if (sc.CheckToken(TK_Float))
|
||||
{
|
||||
sc.MustGetToken('(');
|
||||
FxExpression *exp = ParseExpressionM(sc, cls);
|
||||
sc.MustGetToken(')');
|
||||
return new FxFloatCast(exp);
|
||||
}
|
||||
else if (sc.CheckToken(TK_State))
|
||||
{
|
||||
sc.MustGetToken('(');
|
||||
FxExpression *exp;
|
||||
if (sc.CheckToken(TK_StringConst))
|
||||
{
|
||||
if (sc.String[0] == 0 || sc.Compare("None"))
|
||||
{
|
||||
exp = new FxConstant((FState*)nullptr, sc);
|
||||
}
|
||||
else
|
||||
{
|
||||
exp = new FxMultiNameState(sc.String, sc);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
exp = new FxRuntimeStateIndex(ParseExpressionM(sc, cls));
|
||||
}
|
||||
sc.MustGetToken(')');
|
||||
return exp;
|
||||
}
|
||||
else if (sc.CheckToken(TK_Identifier))
|
||||
{
|
||||
FName identifier = FName(sc.String);
|
||||
|
@ -374,6 +495,29 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
|
|||
case NAME_Random2:
|
||||
return ParseRandom2(sc, cls);
|
||||
default:
|
||||
if (cls != nullptr)
|
||||
{
|
||||
func = dyn_cast<PFunction>(cls->Symbols.FindSymbol(identifier, true));
|
||||
|
||||
// There is an action function ACS_NamedExecuteWithResult which must be ignored here for this to work.
|
||||
if (func != nullptr && identifier != NAME_ACS_NamedExecuteWithResult)
|
||||
{
|
||||
args = new FArgumentList;
|
||||
if (sc.CheckToken('('))
|
||||
{
|
||||
sc.UnGet();
|
||||
ParseFunctionParameters(sc, cls, *args, func, "", nullptr);
|
||||
}
|
||||
if (args->Size() == 0)
|
||||
{
|
||||
delete args;
|
||||
args = nullptr;
|
||||
}
|
||||
|
||||
return new FxVMFunctionCall(func, args, sc);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
if (sc.CheckToken('('))
|
||||
|
@ -392,17 +536,9 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
|
|||
return ParseAtan2(sc, identifier, cls);
|
||||
default:
|
||||
args = new FArgumentList;
|
||||
func = (cls == nullptr) ? nullptr : dyn_cast<PFunction>(cls->Symbols.FindSymbol(identifier, true));
|
||||
try
|
||||
{
|
||||
// There is an action function ACS_NamedExecuteWithResult which must be ignored here for this to work.
|
||||
if (func != NULL && identifier != NAME_ACS_NamedExecuteWithResult)
|
||||
{
|
||||
sc.UnGet();
|
||||
ParseFunctionParameters(sc, cls, *args, func, "", NULL);
|
||||
return new FxVMFunctionCall(func, args, sc);
|
||||
}
|
||||
else if (!sc.CheckToken(')'))
|
||||
if (!sc.CheckToken(')'))
|
||||
{
|
||||
do
|
||||
{
|
||||
|
|
|
@ -62,14 +62,16 @@ class FxJumpStatement;
|
|||
struct FCompileContext
|
||||
{
|
||||
TArray<FxJumpStatement *> Jumps;
|
||||
PPrototype *ReturnProto;
|
||||
PClassActor *Class;
|
||||
|
||||
FCompileContext(PClassActor *cls = nullptr);
|
||||
FCompileContext(PClassActor *cls = nullptr, PPrototype *ret = nullptr);
|
||||
|
||||
PSymbol *FindInClass(FName identifier);
|
||||
PSymbol *FindGlobal(FName identifier);
|
||||
|
||||
void HandleJumps(int token, FxExpression *handler);
|
||||
void CheckReturn(PPrototype *proto, FScriptPosition &pos);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
|
@ -170,14 +172,14 @@ struct ExpVal
|
|||
|
||||
struct ExpEmit
|
||||
{
|
||||
ExpEmit() : RegNum(0), RegType(REGT_NIL), Konst(false), Fixed(false) {}
|
||||
ExpEmit(int reg, int type) : RegNum(reg), RegType(type), Konst(false), Fixed(false) {}
|
||||
ExpEmit(int reg, int type, bool konst) : RegNum(reg), RegType(type), Konst(konst), Fixed(false) {}
|
||||
ExpEmit() : RegNum(0), RegType(REGT_NIL), Konst(false), Fixed(false), Final(false) {}
|
||||
ExpEmit(int reg, int type) : RegNum(reg), RegType(type), Konst(false), Fixed(false), Final(false) {}
|
||||
ExpEmit(int reg, int type, bool konst) : RegNum(reg), RegType(type), Konst(konst), Fixed(false), Final(false) {}
|
||||
ExpEmit(VMFunctionBuilder *build, int type);
|
||||
void Free(VMFunctionBuilder *build);
|
||||
void Reuse(VMFunctionBuilder *build);
|
||||
|
||||
BYTE RegNum, RegType, Konst:1, Fixed:1;
|
||||
BYTE RegNum, RegType, Konst:1, Fixed:1, Final:1;
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
|
@ -201,7 +203,8 @@ public:
|
|||
virtual FxExpression *Resolve(FCompileContext &ctx);
|
||||
|
||||
virtual bool isConstant() const;
|
||||
virtual void RequestAddress();
|
||||
virtual bool RequestAddress();
|
||||
virtual PPrototype *ReturnProto();
|
||||
virtual VMFunction *GetDirectFunction();
|
||||
bool IsNumeric() const { return ValueType != TypeName && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT); }
|
||||
bool IsPointer() const { return ValueType->GetRegType() == REGT_POINTER; }
|
||||
|
@ -469,6 +472,84 @@ public:
|
|||
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);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxAssign
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FxAssign : public FxExpression
|
||||
{
|
||||
FxExpression *Base;
|
||||
FxExpression *Right;
|
||||
bool AddressRequested;
|
||||
bool AddressWritable;
|
||||
|
||||
public:
|
||||
FxAssign(FxExpression *base, FxExpression *right);
|
||||
~FxAssign();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
bool RequestAddress();
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
|
||||
ExpEmit Address;
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxAssignSelf
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FxAssignSelf : public FxExpression
|
||||
{
|
||||
public:
|
||||
FxAssign *Assignment;
|
||||
|
||||
FxAssignSelf(const FScriptPosition &pos);
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxBinary
|
||||
|
@ -670,6 +751,7 @@ public:
|
|||
class FxRandom : public FxExpression
|
||||
{
|
||||
protected:
|
||||
bool EmitTail;
|
||||
FRandom *rng;
|
||||
FxExpression *min, *max;
|
||||
|
||||
|
@ -678,7 +760,7 @@ public:
|
|||
FxRandom(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos);
|
||||
~FxRandom();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
|
||||
PPrototype *ReturnProto();
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
};
|
||||
|
||||
|
@ -724,6 +806,7 @@ public:
|
|||
|
||||
class FxRandom2 : public FxExpression
|
||||
{
|
||||
bool EmitTail;
|
||||
FRandom * rng;
|
||||
FxExpression *mask;
|
||||
|
||||
|
@ -732,7 +815,7 @@ public:
|
|||
FxRandom2(FRandom *, FxExpression *m, const FScriptPosition &pos);
|
||||
~FxRandom2();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
|
||||
PPrototype *ReturnProto();
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
};
|
||||
|
||||
|
@ -753,7 +836,7 @@ public:
|
|||
FxClassMember(FxExpression*, PField*, const FScriptPosition&);
|
||||
~FxClassMember();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
void RequestAddress();
|
||||
bool RequestAddress();
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
};
|
||||
|
||||
|
@ -796,12 +879,13 @@ class FxArrayElement : public FxExpression
|
|||
public:
|
||||
FxExpression *Array;
|
||||
FxExpression *index;
|
||||
//bool AddressRequested;
|
||||
bool AddressRequested;
|
||||
bool AddressWritable;
|
||||
|
||||
FxArrayElement(FxExpression*, FxExpression*);
|
||||
~FxArrayElement();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
//void RequestAddress();
|
||||
bool RequestAddress();
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
};
|
||||
|
||||
|
@ -836,8 +920,9 @@ public:
|
|||
|
||||
class FxActionSpecialCall : public FxExpression
|
||||
{
|
||||
FxExpression *Self;
|
||||
int Special;
|
||||
bool EmitTail;
|
||||
FxExpression *Self;
|
||||
FArgumentList *ArgList;
|
||||
|
||||
public:
|
||||
|
@ -845,6 +930,7 @@ public:
|
|||
FxActionSpecialCall(FxExpression *self, int special, FArgumentList *args, const FScriptPosition &pos);
|
||||
~FxActionSpecialCall();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
PPrototype *ReturnProto();
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
};
|
||||
|
||||
|
@ -875,6 +961,7 @@ public:
|
|||
|
||||
class FxVMFunctionCall : public FxExpression
|
||||
{
|
||||
bool EmitTail;
|
||||
PFunction *Function;
|
||||
FArgumentList *ArgList;
|
||||
|
||||
|
@ -882,13 +969,10 @@ public:
|
|||
FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos);
|
||||
~FxVMFunctionCall();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
PPrototype *ReturnProto();
|
||||
VMFunction *GetDirectFunction();
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
ExpEmit Emit(VMFunctionBuilder *build, bool tailcall);
|
||||
bool CheckEmitCast(VMFunctionBuilder *build, bool returnit, ExpEmit ®);
|
||||
unsigned GetArgCount() const { return ArgList == NULL ? 0 : ArgList->Size(); }
|
||||
PFunction *GetFunction() const { return Function; }
|
||||
VMFunction *GetVMFunction() const { return Function->Variants[0].Implementation; }
|
||||
bool IsDirectFunction();
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
|
@ -1010,10 +1094,10 @@ public:
|
|||
|
||||
class FxReturnStatement : public FxExpression
|
||||
{
|
||||
FxVMFunctionCall *Call;
|
||||
FxExpression *Value;
|
||||
|
||||
public:
|
||||
FxReturnStatement(FxVMFunctionCall *call, const FScriptPosition &pos);
|
||||
FxReturnStatement(FxExpression *value, const FScriptPosition &pos);
|
||||
~FxReturnStatement();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
|
@ -1058,6 +1142,26 @@ public:
|
|||
FxExpression *Resolve(FCompileContext&);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Same as above except for expressions which means it will have to be
|
||||
// evaluated at runtime
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FxRuntimeStateIndex : public FxExpression
|
||||
{
|
||||
bool EmitTail;
|
||||
FxExpression *Index;
|
||||
|
||||
public:
|
||||
FxRuntimeStateIndex(FxExpression *index);
|
||||
~FxRuntimeStateIndex();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
PPrototype *ReturnProto();
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -138,7 +138,8 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c
|
|||
else if (type == TypeState)
|
||||
{
|
||||
// This forces quotation marks around the state name.
|
||||
sc.MustGetToken(TK_StringConst);
|
||||
if (sc.CheckToken(TK_StringConst))
|
||||
{
|
||||
if (sc.String[0] == 0 || sc.Compare("None"))
|
||||
{
|
||||
x = new FxConstant((FState*)NULL, sc);
|
||||
|
@ -156,6 +157,12 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c
|
|||
x = new FxMultiNameState(sc.String, sc);
|
||||
}
|
||||
}
|
||||
else if (!constant)
|
||||
{
|
||||
x = new FxRuntimeStateIndex(ParseExpression(sc, cls));
|
||||
}
|
||||
else sc.MustGetToken(TK_StringConst); // This is for the error.
|
||||
}
|
||||
else if (type->GetClass() == RUNTIME_CLASS(PClassPointer))
|
||||
{ // Actor name
|
||||
sc.SetEscape(true);
|
||||
|
|
|
@ -315,10 +315,10 @@ do_stop:
|
|||
}
|
||||
|
||||
bool hasfinalret;
|
||||
tcall->Code = ParseActions(sc, state, statestring, bag, tcall->Proto, hasfinalret);
|
||||
if (!hasfinalret)
|
||||
tcall->Code = ParseActions(sc, state, statestring, bag, hasfinalret);
|
||||
if (!hasfinalret && tcall->Code != nullptr)
|
||||
{
|
||||
AddImplicitReturn(static_cast<FxSequence*>(tcall->Code), tcall->Proto, sc);
|
||||
static_cast<FxSequence *>(tcall->Code)->Add(new FxReturnStatement(nullptr, sc));
|
||||
}
|
||||
goto endofstate;
|
||||
}
|
||||
|
@ -351,125 +351,37 @@ endofstate:
|
|||
sc.SetEscape(true); // re-enable escape sequences
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// AddImplicitReturn
|
||||
//
|
||||
// Adds an implied return; statement to the end of a code sequence.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void AddImplicitReturn(FxSequence *code, const PPrototype *proto, FScanner &sc)
|
||||
{
|
||||
if (code == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (proto == NULL || proto->ReturnTypes.Size() == 0)
|
||||
{ // Returns nothing. Good. We can safely add an implied return.
|
||||
code->Add(new FxReturnStatement(NULL, sc));
|
||||
}
|
||||
else
|
||||
{ // Something was returned earlier in the sequence. Make it an error
|
||||
// instead of adding an implicit one.
|
||||
sc.ScriptError("Not all paths return a value");
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ReturnCheck
|
||||
//
|
||||
// If proto1 is NULL, returns proto2. If proto2 is NULL, returns proto1.
|
||||
// If neither is null, checks if both prototypes define the same return
|
||||
// types. If not, an error is flagged.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static PPrototype *ReturnCheck(PPrototype *proto1, PPrototype *proto2, FScanner &sc)
|
||||
{
|
||||
if (proto1 == NULL)
|
||||
{
|
||||
return proto2;
|
||||
}
|
||||
if (proto2 == NULL)
|
||||
{
|
||||
return proto1;
|
||||
}
|
||||
// A prototype that defines fewer return types can be compatible with
|
||||
// one that defines more if the shorter one matches the initial types
|
||||
// for the longer one.
|
||||
if (proto2->ReturnTypes.Size() < proto1->ReturnTypes.Size())
|
||||
{ // Make proto1 the shorter one to avoid code duplication below.
|
||||
swapvalues(proto1, proto2);
|
||||
}
|
||||
// If one prototype returns nothing, they both must.
|
||||
if (proto1->ReturnTypes.Size() == 0)
|
||||
{
|
||||
if (proto2->ReturnTypes.Size() == 0)
|
||||
{
|
||||
return proto1;
|
||||
}
|
||||
proto1 = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned i = 0; i < proto1->ReturnTypes.Size(); ++i)
|
||||
{
|
||||
if (proto1->ReturnTypes[i] != proto2->ReturnTypes[i])
|
||||
{ // Incompatible
|
||||
proto1 = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (proto1 == NULL)
|
||||
{
|
||||
sc.ScriptError("Return types are incompatible");
|
||||
}
|
||||
return proto1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ParseActions
|
||||
//
|
||||
// If this action block contains any return statements, the prototype for
|
||||
// one of them will be returned. This is used for deducing the return type
|
||||
// of anonymous functions. All called functions passed to return must have
|
||||
// matching return types.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static FxExpression *ParseIf(FScanner &sc, FState state, FString statestring, Baggage &bag,
|
||||
PPrototype *&retproto, bool &lastwasret)
|
||||
static FxExpression *ParseIf(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &lastwasret)
|
||||
{
|
||||
FxExpression *add, *cond;
|
||||
FxExpression *true_part, *false_part = NULL;
|
||||
PPrototype *true_proto, *false_proto = NULL;
|
||||
FxExpression *true_part, *false_part = nullptr;
|
||||
bool true_ret, false_ret = false;
|
||||
sc.MustGetStringName("(");
|
||||
cond = ParseExpression(sc, bag.Info);
|
||||
sc.MustGetStringName(")");
|
||||
sc.MustGetStringName("{"); // braces are mandatory
|
||||
true_part = ParseActions(sc, state, statestring, bag, true_proto, true_ret);
|
||||
true_part = ParseActions(sc, state, statestring, bag, true_ret);
|
||||
sc.MustGetString();
|
||||
if (sc.Compare("else"))
|
||||
{
|
||||
if (sc.CheckString("if"))
|
||||
{
|
||||
false_part = ParseIf(sc, state, statestring, bag, false_proto, false_ret);
|
||||
false_part = ParseIf(sc, state, statestring, bag, false_ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.MustGetStringName("{"); // braces are still mandatory
|
||||
false_part = ParseActions(sc, state, statestring, bag, false_proto, false_ret);
|
||||
false_part = ParseActions(sc, state, statestring, bag, false_ret);
|
||||
sc.MustGetString();
|
||||
}
|
||||
}
|
||||
add = new FxIfStatement(cond, true_part, false_part, sc);
|
||||
retproto = ReturnCheck(retproto, true_proto, sc);
|
||||
retproto = ReturnCheck(retproto, false_proto, sc);
|
||||
// If one side does not end with a return, we don't consider the if statement
|
||||
// to end with a return. If the else case is missing, it can never be considered
|
||||
// as ending with a return.
|
||||
|
@ -480,11 +392,9 @@ static FxExpression *ParseIf(FScanner &sc, FState state, FString statestring, Ba
|
|||
return add;
|
||||
}
|
||||
|
||||
static FxExpression *ParseWhile(FScanner &sc, FState state, FString statestring, Baggage &bag,
|
||||
PPrototype *&retproto, bool &lastwasret)
|
||||
static FxExpression *ParseWhile(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &lastwasret)
|
||||
{
|
||||
FxExpression *cond, *code;
|
||||
PPrototype *proto;
|
||||
bool ret;
|
||||
|
||||
sc.MustGetStringName("(");
|
||||
|
@ -492,24 +402,21 @@ static FxExpression *ParseWhile(FScanner &sc, FState state, FString statestring,
|
|||
sc.MustGetStringName(")");
|
||||
sc.MustGetStringName("{"); // Enforce braces like for if statements.
|
||||
|
||||
code = ParseActions(sc, state, statestring, bag, proto, ret);
|
||||
code = ParseActions(sc, state, statestring, bag, ret);
|
||||
sc.MustGetString();
|
||||
|
||||
retproto = ReturnCheck(retproto, proto, sc);
|
||||
lastwasret = false; // A while loop always jumps back.
|
||||
|
||||
return new FxWhileLoop(cond, code, sc);
|
||||
}
|
||||
|
||||
static FxExpression *ParseDoWhile(FScanner &sc, FState state, FString statestring, Baggage &bag,
|
||||
PPrototype *&retproto, bool &lastwasret)
|
||||
static FxExpression *ParseDoWhile(FScanner &sc, FState state, FString statestring, Baggage &bag, 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);
|
||||
code = ParseActions(sc, state, statestring, bag, ret);
|
||||
|
||||
sc.MustGetStringName("while");
|
||||
sc.MustGetStringName("(");
|
||||
|
@ -518,20 +425,17 @@ static FxExpression *ParseDoWhile(FScanner &sc, FState state, FString statestrin
|
|||
sc.MustGetStringName(";");
|
||||
sc.MustGetString();
|
||||
|
||||
retproto = ReturnCheck(retproto, proto, sc);
|
||||
lastwasret = false;
|
||||
|
||||
return new FxDoWhileLoop(cond, code, sc);
|
||||
}
|
||||
|
||||
static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, Baggage &bag,
|
||||
PPrototype *&retproto, bool &lastwasret)
|
||||
static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &lastwasret)
|
||||
{
|
||||
FxExpression *init = nullptr;
|
||||
FxExpression *cond = nullptr;
|
||||
FxExpression *iter = nullptr;
|
||||
FxExpression *code = nullptr;
|
||||
PPrototype *proto;
|
||||
bool ret;
|
||||
|
||||
// Parse the statements.
|
||||
|
@ -539,7 +443,8 @@ static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, B
|
|||
sc.MustGetString();
|
||||
if (!sc.Compare(";"))
|
||||
{
|
||||
init = ParseAction(sc, state, statestring, bag); // That's all DECORATE can handle for now.
|
||||
sc.UnGet();
|
||||
init = ParseExpression(sc, bag.Info);
|
||||
sc.MustGetStringName(";");
|
||||
}
|
||||
sc.MustGetString();
|
||||
|
@ -552,30 +457,28 @@ static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, B
|
|||
sc.MustGetString();
|
||||
if (!sc.Compare(")"))
|
||||
{
|
||||
iter = ParseAction(sc, state, statestring, bag);
|
||||
sc.UnGet();
|
||||
iter = ParseExpression(sc, bag.Info);
|
||||
sc.MustGetStringName(")");
|
||||
}
|
||||
|
||||
// Now parse the loop's content.
|
||||
sc.MustGetStringName("{"); // Enforce braces like for if statements.
|
||||
code = ParseActions(sc, state, statestring, bag, proto, ret);
|
||||
code = ParseActions(sc, state, statestring, bag, 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)
|
||||
FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &endswithret)
|
||||
{
|
||||
// If it's not a '{', then it should be a single action.
|
||||
// Otherwise, it's a sequence of actions.
|
||||
if (!sc.Compare("{"))
|
||||
{
|
||||
FxVMFunctionCall *call = ParseAction(sc, state, statestring, bag);
|
||||
retproto = call->GetVMFunction()->Proto;
|
||||
endswithret = true;
|
||||
return new FxReturnStatement(call, sc);
|
||||
}
|
||||
|
@ -583,7 +486,6 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg
|
|||
const FScriptPosition pos(sc);
|
||||
|
||||
FxSequence *seq = NULL;
|
||||
PPrototype *proto = NULL;
|
||||
bool lastwasret = false;
|
||||
|
||||
sc.MustGetString();
|
||||
|
@ -593,38 +495,31 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg
|
|||
lastwasret = false;
|
||||
if (sc.Compare("if"))
|
||||
{ // Handle an if statement
|
||||
add = ParseIf(sc, state, statestring, bag, proto, lastwasret);
|
||||
add = ParseIf(sc, state, statestring, bag, lastwasret);
|
||||
}
|
||||
else if (sc.Compare("while"))
|
||||
{ // Handle a while loop
|
||||
add = ParseWhile(sc, state, statestring, bag, proto, lastwasret);
|
||||
add = ParseWhile(sc, state, statestring, bag, lastwasret);
|
||||
}
|
||||
else if (sc.Compare("do"))
|
||||
{ // Handle a do-while loop
|
||||
add = ParseDoWhile(sc, state, statestring, bag, proto, lastwasret);
|
||||
add = ParseDoWhile(sc, state, statestring, bag, lastwasret);
|
||||
}
|
||||
else if (sc.Compare("for"))
|
||||
{ // Handle a for loop
|
||||
add = ParseFor(sc, state, statestring, bag, proto, lastwasret);
|
||||
add = ParseFor(sc, state, statestring, bag, lastwasret);
|
||||
}
|
||||
else if (sc.Compare("return"))
|
||||
{ // Handle a return statement
|
||||
lastwasret = true;
|
||||
FxVMFunctionCall *retexp = NULL;
|
||||
PPrototype *retproto;
|
||||
FxExpression *retexp = nullptr;
|
||||
sc.MustGetString();
|
||||
if (!sc.Compare(";"))
|
||||
{
|
||||
retexp = ParseAction(sc, state, statestring, bag);
|
||||
sc.UnGet();
|
||||
retexp = ParseExpression(sc, bag.Info);
|
||||
sc.MustGetStringName(";");
|
||||
retproto = retexp->GetVMFunction()->Proto;
|
||||
}
|
||||
else
|
||||
{ // Returning nothing; we still need a prototype for that.
|
||||
TArray<PType *> notypes(0);
|
||||
retproto = NewPrototype(notypes, notypes);
|
||||
}
|
||||
proto = ReturnCheck(proto, retproto, sc);
|
||||
sc.MustGetString();
|
||||
add = new FxReturnStatement(retexp, sc);
|
||||
}
|
||||
|
@ -641,8 +536,9 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg
|
|||
sc.MustGetString();
|
||||
}
|
||||
else
|
||||
{ // Handle a regular action function call
|
||||
add = ParseAction(sc, state, statestring, bag);
|
||||
{ // Handle a regular expression
|
||||
sc.UnGet();
|
||||
add = ParseExpression(sc, bag.Info);
|
||||
sc.MustGetStringName(";");
|
||||
sc.MustGetString();
|
||||
}
|
||||
|
@ -657,7 +553,6 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg
|
|||
}
|
||||
}
|
||||
endswithret = lastwasret;
|
||||
retproto = proto;
|
||||
return seq;
|
||||
}
|
||||
|
||||
|
|
|
@ -430,6 +430,11 @@ C98F79709BD7E0E4C19026AB9575EC6F // cc-cod.zip:codlev.wad map07
|
|||
maskedmidtex
|
||||
}
|
||||
|
||||
7B82B12A6990E09553B12FDB4E3824A0 // hti.wad map01
|
||||
{
|
||||
teleport
|
||||
}
|
||||
|
||||
D7F6E9F08C39A17026349A04F8C0B0BE // Return to Hadron, e1m9
|
||||
19D03FFC875589E21EDBB7AB74EF4AEF // Return to Hadron, e1m9, 2016.01.03 update
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue