mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-11 07:11:54 +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)
|
||||
{
|
||||
CHECKRESOLVED();
|
||||
Outer = ctx.Block;
|
||||
ctx.Block = this;
|
||||
for (unsigned i = 0; i < Expressions.Size(); ++i)
|
||||
{
|
||||
if (NULL == (Expressions[i] = Expressions[i]->Resolve(ctx)))
|
||||
{
|
||||
ctx.Block = Outer;
|
||||
delete this;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
ctx.Block = Outer;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -5048,6 +5052,11 @@ ExpEmit FxCompoundStatement::Emit(VMFunctionBuilder *build)
|
|||
// Throw away any result. We don't care about it.
|
||||
v.Free(build);
|
||||
}
|
||||
// Release all local variables in this block.
|
||||
for (auto l : LocalVars)
|
||||
{
|
||||
l->Release(build);
|
||||
}
|
||||
return ExpEmit();
|
||||
}
|
||||
|
||||
|
@ -5066,6 +5075,52 @@ VMFunction *FxCompoundStatement::GetDirectFunction()
|
|||
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
|
||||
|
@ -6142,3 +6197,87 @@ ExpEmit FxDamageValue::Emit(VMFunctionBuilder *build)
|
|||
|
||||
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;
|
||||
class FxLoopStatement;
|
||||
class FxCompoundStatement;
|
||||
|
||||
struct FCompileContext
|
||||
{
|
||||
FxLoopStatement *Loop;
|
||||
FxLoopStatement *Loop = nullptr;
|
||||
FxCompoundStatement *Block = nullptr;
|
||||
PPrototype *ReturnProto;
|
||||
PFunction *Function; // The function that is currently being compiled (or nullptr for constant evaluation.)
|
||||
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;
|
||||
}
|
||||
|
||||
void *GetPointer() const
|
||||
{
|
||||
int regtype = Type->GetRegType();
|
||||
return regtype == REGT_POINTER ? pointer : nullptr;
|
||||
}
|
||||
|
||||
const FString GetString() const
|
||||
{
|
||||
return Type == TypeString ? *(FString *)&pointer : Type == TypeName ? FString(FName(ENamedName(Int)).GetChars()) : "";
|
||||
|
@ -1082,10 +1090,15 @@ public:
|
|||
// FxCompoundStatement
|
||||
//
|
||||
//==========================================================================
|
||||
class FxLocalVariableDeclaration;
|
||||
|
||||
class FxCompoundStatement : public FxExpression
|
||||
{
|
||||
TArray<FxLocalVariableDeclaration *> LocalVars;
|
||||
TDeletingArray<FxExpression *> Expressions;
|
||||
FxCompoundStatement *Outer = nullptr;
|
||||
|
||||
friend class FxLocalVariableDeclaration;
|
||||
|
||||
public:
|
||||
FxCompoundStatement(const FScriptPosition &pos) : FxExpression(pos) {}
|
||||
|
@ -1093,6 +1106,8 @@ public:
|
|||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
void Add(FxExpression *expr) { if (expr != NULL) Expressions.Push(expr); }
|
||||
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
|
||||
|
|
|
@ -144,6 +144,7 @@ inline void ResetBaggage (Baggage *bag, PClassActor *stateclass)
|
|||
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 ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray<FxExpression *> &out_params,
|
||||
PFunction *afd, FString statestring, FStateDefinitions *statedef);
|
||||
|
|
|
@ -2313,8 +2313,27 @@ void ZCCCompiler::CompileStates()
|
|||
|
||||
FxExpression *ZCCCompiler::ConvertAST(ZCC_TreeNode *ast)
|
||||
{
|
||||
// FxReturnStatement will have to be done more intelligently, of course.
|
||||
return new FxReturnStatement(ConvertNode(ast), *ast);
|
||||
// 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.
|
||||
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)
|
||||
|
@ -2514,8 +2533,42 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
|
|||
|
||||
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.
|
||||
I_Error("ConvertNode encountered unsupported node of type %d", ast->NodeType);
|
||||
return nullptr;
|
||||
|
|
Loading…
Reference in a new issue