This commit is contained in:
Christoph Oelckers 2016-08-07 22:13:55 +02:00
commit 9a5cbbe6d8
18 changed files with 1077 additions and 315 deletions

View file

@ -509,8 +509,10 @@ 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")
set( CMAKE_CXX_FLAGS "-Wno-inconsistent-missing-override ${CMAKE_CXX_FLAGS}" )
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}" )

View file

@ -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 }
};

View file

@ -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);
//==========================================================================
//

View file

@ -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 -------------------------------------------------------

View file

@ -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

View file

@ -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 },

View file

@ -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;
}

View file

@ -654,6 +654,7 @@ xx(DecoCallLineSpecial)
xx(DecoNameToClass)
xx(DecoFindMultiNameState)
xx(DecoFindSingleNameState)
xx(DecoHandleRuntimeState)
xx(Damage)
// basic type names

View file

@ -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);
}

View file

@ -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);
// 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);
// 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 != NULL)
// 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 == 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);
}
sfunc->Proto = NewPrototype(tcall->Proto->ReturnTypes, 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);

View file

@ -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)

View file

@ -631,38 +631,38 @@ void InitThingdef()
// Define some member variables we feel like exposing to the user
PSymbolTable &symt = RUNTIME_CLASS(AActor)->Symbols;
PType *array5 = NewArray(TypeSInt32, 5);
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_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_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_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_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|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|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|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|VARF_ReadOnly, myoffsetof(AActor, threshold)));
symt.AddSymbol(new PField(NAME_DefThreshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, DefThreshold)));
}

View file

@ -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
{
@ -420,7 +556,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
}
break;
}
}
}
else
{
return new FxIdentifier(identifier, sc);

View file

@ -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 &reg);
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

View file

@ -138,23 +138,30 @@ 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.String[0] == 0 || sc.Compare("None"))
if (sc.CheckToken(TK_StringConst))
{
x = new FxConstant((FState*)NULL, sc);
}
else if (sc.Compare("*"))
{
if (constant)
if (sc.String[0] == 0 || sc.Compare("None"))
{
x = new FxConstant((FState*)(intptr_t)-1, sc);
x = new FxConstant((FState*)NULL, sc);
}
else if (sc.Compare("*"))
{
if (constant)
{
x = new FxConstant((FState*)(intptr_t)-1, sc);
}
else sc.ScriptError("Invalid state name '*'");
}
else
{
x = new FxMultiNameState(sc.String, sc);
}
else sc.ScriptError("Invalid state name '*'");
}
else
else if (!constant)
{
x = new FxMultiNameState(sc.String, sc);
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

View file

@ -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;
}

View file

@ -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
{