mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-28 06:42:09 +00:00
- added processing of compound statements to the compiler. This means that anonymous functions without control statements are generating code now.
- added local variable declarations to the code generator. This is not tested yet, that will come with the next commit.
This commit is contained in:
parent
8a6230d64a
commit
2d85efce2a
4 changed files with 232 additions and 5 deletions
|
@ -5023,14 +5023,18 @@ ExpEmit FxFlopFunctionCall::Emit(VMFunctionBuilder *build)
|
||||||
FxExpression *FxCompoundStatement::Resolve(FCompileContext &ctx)
|
FxExpression *FxCompoundStatement::Resolve(FCompileContext &ctx)
|
||||||
{
|
{
|
||||||
CHECKRESOLVED();
|
CHECKRESOLVED();
|
||||||
|
Outer = ctx.Block;
|
||||||
|
ctx.Block = this;
|
||||||
for (unsigned i = 0; i < Expressions.Size(); ++i)
|
for (unsigned i = 0; i < Expressions.Size(); ++i)
|
||||||
{
|
{
|
||||||
if (NULL == (Expressions[i] = Expressions[i]->Resolve(ctx)))
|
if (NULL == (Expressions[i] = Expressions[i]->Resolve(ctx)))
|
||||||
{
|
{
|
||||||
|
ctx.Block = Outer;
|
||||||
delete this;
|
delete this;
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ctx.Block = Outer;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5048,6 +5052,11 @@ ExpEmit FxCompoundStatement::Emit(VMFunctionBuilder *build)
|
||||||
// Throw away any result. We don't care about it.
|
// Throw away any result. We don't care about it.
|
||||||
v.Free(build);
|
v.Free(build);
|
||||||
}
|
}
|
||||||
|
// Release all local variables in this block.
|
||||||
|
for (auto l : LocalVars)
|
||||||
|
{
|
||||||
|
l->Release(build);
|
||||||
|
}
|
||||||
return ExpEmit();
|
return ExpEmit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5066,6 +5075,52 @@ VMFunction *FxCompoundStatement::GetDirectFunction()
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxCompoundStatement :: FindLocalVariable
|
||||||
|
//
|
||||||
|
// Looks for a variable name in any of the containing compound statements
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FxLocalVariableDeclaration *FxCompoundStatement::FindLocalVariable(FName name)
|
||||||
|
{
|
||||||
|
auto block = this;
|
||||||
|
while (block != nullptr)
|
||||||
|
{
|
||||||
|
for (auto l : block->LocalVars)
|
||||||
|
{
|
||||||
|
if (l->Name == name)
|
||||||
|
{
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
block = block->Outer;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxCompoundStatement :: CheckLocalVariable
|
||||||
|
//
|
||||||
|
// Checks if the current block already contains a local variable
|
||||||
|
// of the given name.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
bool FxCompoundStatement::CheckLocalVariable(FName name)
|
||||||
|
{
|
||||||
|
for (auto l : LocalVars)
|
||||||
|
{
|
||||||
|
if (l->Name == name)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// FxIfStatement
|
// FxIfStatement
|
||||||
|
@ -6142,3 +6197,87 @@ ExpEmit FxDamageValue::Emit(VMFunctionBuilder *build)
|
||||||
|
|
||||||
return ExpEmit();
|
return ExpEmit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// declares a single local variable (no arrays)
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FxLocalVariableDeclaration::FxLocalVariableDeclaration(PType *type, FName name, FxExpression *initval, const FScriptPosition &p)
|
||||||
|
:FxExpression(p)
|
||||||
|
{
|
||||||
|
ValueType = type;
|
||||||
|
Name = name;
|
||||||
|
Init = initval == nullptr? nullptr : new FxTypeCast(initval, type, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
FxExpression *FxLocalVariableDeclaration::Resolve(FCompileContext &ctx)
|
||||||
|
{
|
||||||
|
CHECKRESOLVED();
|
||||||
|
SAFE_RESOLVE_OPT(Init, ctx);
|
||||||
|
if (ctx.Block == nullptr)
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Variable declaration outside compound statement");
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
ctx.Block->LocalVars.Push(this);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build)
|
||||||
|
{
|
||||||
|
if (Init == nullptr)
|
||||||
|
{
|
||||||
|
RegNum = build->Registers[ValueType->GetRegType()].Get(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ExpEmit emitval = Init->Emit(build);
|
||||||
|
|
||||||
|
int regtype = emitval.RegType;
|
||||||
|
if (regtype < REGT_INT || regtype > REGT_TYPE)
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Attempted to assign a non-value");
|
||||||
|
return ExpEmit();
|
||||||
|
}
|
||||||
|
if (emitval.Konst)
|
||||||
|
{
|
||||||
|
auto constval = static_cast<FxConstant *>(Init);
|
||||||
|
RegNum = build->Registers[regtype].Get(1);
|
||||||
|
switch (regtype)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case REGT_INT:
|
||||||
|
build->Emit(OP_LK, build->GetConstantInt(constval->GetValue().GetInt()), RegNum);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REGT_FLOAT:
|
||||||
|
build->Emit(OP_LKF, build->GetConstantFloat(constval->GetValue().GetFloat()), RegNum);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REGT_POINTER:
|
||||||
|
build->Emit(OP_LKP, build->GetConstantAddress(constval->GetValue().GetPointer(), ATAG_GENERIC), RegNum);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REGT_STRING:
|
||||||
|
build->Emit(OP_LKS, build->GetConstantString(constval->GetValue().GetString()), RegNum);
|
||||||
|
}
|
||||||
|
emitval.Free(build);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// take over the register that got allocated while emitting the Init expression.
|
||||||
|
RegNum = emitval.RegNum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ExpEmit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FxLocalVariableDeclaration::Release(VMFunctionBuilder *build)
|
||||||
|
{
|
||||||
|
// Release the register after the containing block gets closed
|
||||||
|
assert(RegNum != -1);
|
||||||
|
build->Registers[ValueType->GetRegType()].Return(RegNum, 1);
|
||||||
|
}
|
||||||
|
|
|
@ -63,10 +63,12 @@ class FxJumpStatement;
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
struct FScriptPosition;
|
struct FScriptPosition;
|
||||||
class FxLoopStatement;
|
class FxLoopStatement;
|
||||||
|
class FxCompoundStatement;
|
||||||
|
|
||||||
struct FCompileContext
|
struct FCompileContext
|
||||||
{
|
{
|
||||||
FxLoopStatement *Loop;
|
FxLoopStatement *Loop = nullptr;
|
||||||
|
FxCompoundStatement *Block = nullptr;
|
||||||
PPrototype *ReturnProto;
|
PPrototype *ReturnProto;
|
||||||
PFunction *Function; // The function that is currently being compiled (or nullptr for constant evaluation.)
|
PFunction *Function; // The function that is currently being compiled (or nullptr for constant evaluation.)
|
||||||
PClass *Class; // The type of the owning class.
|
PClass *Class; // The type of the owning class.
|
||||||
|
@ -162,6 +164,12 @@ struct ExpVal
|
||||||
return regtype == REGT_INT ? double(Int) : regtype == REGT_FLOAT ? Float : 0;
|
return regtype == REGT_INT ? double(Int) : regtype == REGT_FLOAT ? Float : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *GetPointer() const
|
||||||
|
{
|
||||||
|
int regtype = Type->GetRegType();
|
||||||
|
return regtype == REGT_POINTER ? pointer : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
const FString GetString() const
|
const FString GetString() const
|
||||||
{
|
{
|
||||||
return Type == TypeString ? *(FString *)&pointer : Type == TypeName ? FString(FName(ENamedName(Int)).GetChars()) : "";
|
return Type == TypeString ? *(FString *)&pointer : Type == TypeName ? FString(FName(ENamedName(Int)).GetChars()) : "";
|
||||||
|
@ -1082,10 +1090,15 @@ public:
|
||||||
// FxCompoundStatement
|
// FxCompoundStatement
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
class FxLocalVariableDeclaration;
|
||||||
|
|
||||||
class FxCompoundStatement : public FxExpression
|
class FxCompoundStatement : public FxExpression
|
||||||
{
|
{
|
||||||
|
TArray<FxLocalVariableDeclaration *> LocalVars;
|
||||||
TDeletingArray<FxExpression *> Expressions;
|
TDeletingArray<FxExpression *> Expressions;
|
||||||
|
FxCompoundStatement *Outer = nullptr;
|
||||||
|
|
||||||
|
friend class FxLocalVariableDeclaration;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FxCompoundStatement(const FScriptPosition &pos) : FxExpression(pos) {}
|
FxCompoundStatement(const FScriptPosition &pos) : FxExpression(pos) {}
|
||||||
|
@ -1093,6 +1106,8 @@ public:
|
||||||
ExpEmit Emit(VMFunctionBuilder *build);
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
void Add(FxExpression *expr) { if (expr != NULL) Expressions.Push(expr); }
|
void Add(FxExpression *expr) { if (expr != NULL) Expressions.Push(expr); }
|
||||||
VMFunction *GetDirectFunction();
|
VMFunction *GetDirectFunction();
|
||||||
|
FxLocalVariableDeclaration *FindLocalVariable(FName name);
|
||||||
|
bool CheckLocalVariable(FName name);
|
||||||
};
|
};
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -1341,7 +1356,26 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
FxExpression *ParseExpression (FScanner &sc, PClassActor *cls, bool mustresolve = false);
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
class FxLocalVariableDeclaration : public FxExpression
|
||||||
|
{
|
||||||
|
friend class FxCompoundStatement;
|
||||||
|
|
||||||
|
FName Name;
|
||||||
|
FxExpression *Init;
|
||||||
|
int RegNum = -1;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FxLocalVariableDeclaration(PType *type, FName name, FxExpression *initval, const FScriptPosition &p);
|
||||||
|
FxExpression *Resolve(FCompileContext&);
|
||||||
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
|
void Release(VMFunctionBuilder *build);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -144,6 +144,7 @@ inline void ResetBaggage (Baggage *bag, PClassActor *stateclass)
|
||||||
AFuncDesc *FindFunction(const char * string);
|
AFuncDesc *FindFunction(const char * string);
|
||||||
|
|
||||||
|
|
||||||
|
FxExpression *ParseExpression(FScanner &sc, PClassActor *cls, bool mustresolve = false);
|
||||||
void ParseStates(FScanner &sc, PClassActor *actor, AActor *defaults, Baggage &bag);
|
void ParseStates(FScanner &sc, PClassActor *actor, AActor *defaults, Baggage &bag);
|
||||||
void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray<FxExpression *> &out_params,
|
void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray<FxExpression *> &out_params,
|
||||||
PFunction *afd, FString statestring, FStateDefinitions *statedef);
|
PFunction *afd, FString statestring, FStateDefinitions *statedef);
|
||||||
|
|
|
@ -2313,8 +2313,27 @@ void ZCCCompiler::CompileStates()
|
||||||
|
|
||||||
FxExpression *ZCCCompiler::ConvertAST(ZCC_TreeNode *ast)
|
FxExpression *ZCCCompiler::ConvertAST(ZCC_TreeNode *ast)
|
||||||
{
|
{
|
||||||
// FxReturnStatement will have to be done more intelligently, of course.
|
// there are two possibilities here: either a single function call or a compound statement. For a compound statement we also need to check if the last thing added was a return.
|
||||||
return new FxReturnStatement(ConvertNode(ast), *ast);
|
if (ast->NodeType == AST_ExprFuncCall)
|
||||||
|
{
|
||||||
|
return new FxReturnStatement(ConvertNode(ast), *ast);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This must be done here so that we can check for a trailing return statement.
|
||||||
|
auto x = new FxCompoundStatement(*ast);
|
||||||
|
auto compound = static_cast<ZCC_CompoundStmt *>(ast);
|
||||||
|
bool isreturn = false;
|
||||||
|
auto node = compound->Content;
|
||||||
|
if (node != nullptr) do
|
||||||
|
{
|
||||||
|
x->Add(ConvertNode(node));
|
||||||
|
isreturn = node->NodeType == AST_ReturnStmt;
|
||||||
|
node = static_cast<decltype(node)>(node->SiblingNext);
|
||||||
|
} while (node != compound->Content);
|
||||||
|
if (!isreturn) x->Add(new FxReturnStatement(nullptr, *ast));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
|
FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
|
||||||
|
@ -2514,8 +2533,42 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
|
||||||
|
|
||||||
return new FxConditional(condition, left, right);
|
return new FxConditional(condition, left, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case AST_ExpressionStmt:
|
||||||
|
return ConvertNode(static_cast<ZCC_ExpressionStmt *>(ast)->Expression);
|
||||||
|
|
||||||
|
case AST_ReturnStmt:
|
||||||
|
{
|
||||||
|
auto ret = static_cast<ZCC_ReturnStmt *>(ast);
|
||||||
|
FArgumentList *args = ConvertNodeList(ret->Values);
|
||||||
|
if (args->Size() == 0)
|
||||||
|
{
|
||||||
|
return new FxReturnStatement(nullptr, *ast);
|
||||||
|
}
|
||||||
|
else if (args->Size() == 1)
|
||||||
|
{
|
||||||
|
return new FxReturnStatement((*args)[0], *ast);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Error(ast, "Return with multiple values not implemented yet.");
|
||||||
|
return new FxReturnStatement(nullptr, *ast);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case AST_CompoundStmt:
|
||||||
|
{
|
||||||
|
auto x = new FxCompoundStatement(*ast);
|
||||||
|
auto compound = static_cast<ZCC_CompoundStmt *>(ast);
|
||||||
|
auto node = compound->Content;
|
||||||
|
if (node != nullptr) do
|
||||||
|
{
|
||||||
|
x->Add(ConvertNode(node));
|
||||||
|
node = static_cast<decltype(node)>(node->SiblingNext);
|
||||||
|
} while (node != compound->Content);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
}
|
||||||
// only for development. I_Error is more convenient here than a normal error.
|
// only for development. I_Error is more convenient here than a normal error.
|
||||||
I_Error("ConvertNode encountered unsupported node of type %d", ast->NodeType);
|
I_Error("ConvertNode encountered unsupported node of type %d", ast->NodeType);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
Loading…
Reference in a new issue