- Changed ZCCCompiler::Simplify to allow running in constant and non-constant mode. The difference is that non-constant mode does not attempt to simplify function name expressions because these cannot be processed without destroying them, if some identifier in there is not referencing a symbol, which is quite common.

This commit is contained in:
Christoph Oelckers 2016-10-16 01:33:36 +02:00
parent d6ce60f63a
commit 847b8c45ef
2 changed files with 35 additions and 21 deletions

View file

@ -685,7 +685,7 @@ bool ZCCCompiler::CompileConstant(ZCC_ConstantDef *def, PSymbolTable *sym)
assert(def->Symbol == nullptr); assert(def->Symbol == nullptr);
def->Symbol = DEFINING_CONST; // avoid recursion def->Symbol = DEFINING_CONST; // avoid recursion
ZCC_Expression *val = Simplify(def->Value, sym); ZCC_Expression *val = Simplify(def->Value, sym, true);
def->Value = val; def->Value = val;
if (def->Symbol == DEFINING_CONST) def->Symbol = nullptr; if (def->Symbol == DEFINING_CONST) def->Symbol = nullptr;
return (val->NodeType == AST_ExprConstant); return (val->NodeType == AST_ExprConstant);
@ -705,7 +705,13 @@ bool ZCCCompiler::CompileConstant(ZCC_ConstantDef *def, PSymbolTable *sym)
// //
//========================================================================== //==========================================================================
ZCC_Expression *ZCCCompiler::Simplify(ZCC_Expression *root, PSymbolTable *sym) ZCC_Expression *ZCCCompiler::Simplify(ZCC_Expression *root, PSymbolTable *sym, bool wantconstant)
{
SimplifyingConstant = wantconstant;
return DoSimplify(root, sym);
}
ZCC_Expression *ZCCCompiler::DoSimplify(ZCC_Expression *root, PSymbolTable *sym)
{ {
if (root->NodeType == AST_ExprUnary) if (root->NodeType == AST_ExprUnary)
{ {
@ -738,7 +744,7 @@ ZCC_Expression *ZCCCompiler::Simplify(ZCC_Expression *root, PSymbolTable *sym)
ZCC_Expression *ZCCCompiler::SimplifyUnary(ZCC_ExprUnary *unary, PSymbolTable *sym) ZCC_Expression *ZCCCompiler::SimplifyUnary(ZCC_ExprUnary *unary, PSymbolTable *sym)
{ {
unary->Operand = Simplify(unary->Operand, sym); unary->Operand = DoSimplify(unary->Operand, sym);
if (unary->Operand->Type == nullptr) if (unary->Operand->Type == nullptr)
{ {
return unary; return unary;
@ -763,8 +769,8 @@ ZCC_Expression *ZCCCompiler::SimplifyUnary(ZCC_ExprUnary *unary, PSymbolTable *s
ZCC_Expression *ZCCCompiler::SimplifyBinary(ZCC_ExprBinary *binary, PSymbolTable *sym) ZCC_Expression *ZCCCompiler::SimplifyBinary(ZCC_ExprBinary *binary, PSymbolTable *sym)
{ {
binary->Left = Simplify(binary->Left, sym); binary->Left = DoSimplify(binary->Left, sym);
binary->Right = Simplify(binary->Right, sym); binary->Right = DoSimplify(binary->Right, sym);
if (binary->Left->Type == nullptr || binary->Right->Type == nullptr) if (binary->Left->Type == nullptr || binary->Right->Type == nullptr)
{ {
// We do not know yet what this is so we cannot promote it (yet.) // We do not know yet what this is so we cannot promote it (yet.)
@ -794,7 +800,8 @@ ZCC_Expression *ZCCCompiler::SimplifyMemberAccess(ZCC_ExprMemberAccess *dotop, P
{ {
PSymbolTable *symtable; PSymbolTable *symtable;
dotop->Left = Simplify(dotop->Left, symt); // TBD: Is it safe to simplify the left side here when not processing a constant?
dotop->Left = DoSimplify(dotop->Left, symt);
if (dotop->Left->Operation == PEX_TypeRef) if (dotop->Left->Operation == PEX_TypeRef)
{ // Type refs can be evaluated now. { // Type refs can be evaluated now.
@ -842,7 +849,6 @@ ZCC_Expression *ZCCCompiler::SimplifyFunctionCall(ZCC_ExprFuncCall *callop, PSym
ZCC_FuncParm *parm; ZCC_FuncParm *parm;
int parmcount = 0; int parmcount = 0;
callop->Function = Simplify(callop->Function, sym);
parm = callop->Parameters; parm = callop->Parameters;
if (parm != NULL) if (parm != NULL)
{ {
@ -850,11 +856,18 @@ ZCC_Expression *ZCCCompiler::SimplifyFunctionCall(ZCC_ExprFuncCall *callop, PSym
{ {
parmcount++; parmcount++;
assert(parm->NodeType == AST_FuncParm); assert(parm->NodeType == AST_FuncParm);
parm->Value = Simplify(parm->Value, sym); parm->Value = DoSimplify(parm->Value, sym);
parm = static_cast<ZCC_FuncParm *>(parm->SiblingNext); parm = static_cast<ZCC_FuncParm *>(parm->SiblingNext);
} }
while (parm != callop->Parameters); while (parm != callop->Parameters);
} }
// Only simplify the 'function' part if we want to retrieve a constant.
// This is necessary to evaluate the type casts, but for actual functions
// the simplification process is destructive and has to be avoided.
if (SimplifyingConstant)
{
callop->Function = DoSimplify(callop->Function, sym);
}
// If the left side is a type ref, then this is actually a cast // If the left side is a type ref, then this is actually a cast
// and not a function call. // and not a function call.
if (callop->Function->Operation == PEX_TypeRef) if (callop->Function->Operation == PEX_TypeRef)
@ -1440,11 +1453,11 @@ PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, PSymbolTable *symt)
PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PSymbolTable *sym) PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PSymbolTable *sym)
{ {
// The duplicate Simplify call is necessary because if the head node gets replaced there is no way to detect the end of the list otherwise. // The duplicate Simplify call is necessary because if the head node gets replaced there is no way to detect the end of the list otherwise.
arraysize = Simplify(arraysize, sym); arraysize = Simplify(arraysize, sym, true);
ZCC_Expression *val; ZCC_Expression *val;
do do
{ {
val = Simplify(arraysize, sym); val = Simplify(arraysize, sym, true);
if (val->Operation != PEX_ConstValue || !val->Type->IsA(RUNTIME_CLASS(PInt))) if (val->Operation != PEX_ConstValue || !val->Type->IsA(RUNTIME_CLASS(PInt)))
{ {
Error(arraysize, "Array index must be an integer constant"); Error(arraysize, "Array index must be an integer constant");
@ -1556,7 +1569,7 @@ void ZCCCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *proper
Error(property, "%s: arguments missing", prop->name); Error(property, "%s: arguments missing", prop->name);
return; return;
} }
property->Values = Simplify(property->Values, &bag.Info->Symbols); // need to do this before the loop so that we can find the head node again. property->Values = Simplify(property->Values, &bag.Info->Symbols, true); // need to do this before the loop so that we can find the head node again.
const char * p = prop->params; const char * p = prop->params;
auto exp = property->Values; auto exp = property->Values;
@ -1634,7 +1647,7 @@ void ZCCCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *proper
params.Push(conv); params.Push(conv);
params[0].i++; params[0].i++;
} }
exp = Simplify(static_cast<ZCC_Expression *>(exp->SiblingNext), &bag.Info->Symbols); exp = Simplify(static_cast<ZCC_Expression *>(exp->SiblingNext), &bag.Info->Symbols, true);
} while (exp != property->Values); } while (exp != property->Values);
goto endofparm; goto endofparm;
} }
@ -1652,7 +1665,7 @@ void ZCCCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *proper
} }
params.Push(conv); params.Push(conv);
params[0].i++; params[0].i++;
exp = Simplify(static_cast<ZCC_Expression *>(exp->SiblingNext), &bag.Info->Symbols); exp = Simplify(static_cast<ZCC_Expression *>(exp->SiblingNext), &bag.Info->Symbols, true);
endofparm: endofparm:
p++; p++;
// Skip the DECORATE 'no comma' marker // Skip the DECORATE 'no comma' marker
@ -1944,7 +1957,7 @@ void ZCCCompiler::InitFunctions()
if (p->Flags & ZCC_Out) flags |= VARF_Out; if (p->Flags & ZCC_Out) flags |= VARF_Out;
if (p->Default != nullptr) if (p->Default != nullptr)
{ {
auto val = Simplify(p->Default, &c->Type()->Symbols); auto val = Simplify(p->Default, &c->Type()->Symbols, true);
flags |= VARF_Optional; flags |= VARF_Optional;
if (val->Operation != PEX_ConstValue) if (val->Operation != PEX_ConstValue)
{ {
@ -2101,10 +2114,9 @@ void ZCCCompiler::CompileStates()
state.sprite = GetSpriteIndex(sl->Sprite->GetChars()); state.sprite = GetSpriteIndex(sl->Sprite->GetChars());
} }
// It is important to call CheckRandom before Simplify, because Simplify will resolve the function's name to nonsense // It is important to call CheckRandom before Simplify, because Simplify will resolve the function's name to nonsense
// and there is little point fixing it because it is essentially useless outside of resolving constants.
if (CheckRandom(sl->Duration)) if (CheckRandom(sl->Duration))
{ {
auto func = static_cast<ZCC_ExprFuncCall *>(Simplify(sl->Duration, &c->Type()->Symbols)); auto func = static_cast<ZCC_ExprFuncCall *>(Simplify(sl->Duration, &c->Type()->Symbols, true));
if (func->Parameters == func->Parameters->SiblingNext || func->Parameters != func->Parameters->SiblingNext->SiblingNext) if (func->Parameters == func->Parameters->SiblingNext || func->Parameters != func->Parameters->SiblingNext->SiblingNext)
{ {
Error(sl, "Random duration requires exactly 2 parameters"); Error(sl, "Random duration requires exactly 2 parameters");
@ -2117,7 +2129,7 @@ void ZCCCompiler::CompileStates()
} }
else else
{ {
auto duration = Simplify(sl->Duration, &c->Type()->Symbols); auto duration = Simplify(sl->Duration, &c->Type()->Symbols, true);
if (duration->Operation == PEX_ConstValue) if (duration->Operation == PEX_ConstValue)
{ {
state.Tics = (int16_t)clamp<int>(GetInt(duration), -1, INT16_MAX); state.Tics = (int16_t)clamp<int>(GetInt(duration), -1, INT16_MAX);
@ -2141,8 +2153,8 @@ void ZCCCompiler::CompileStates()
} }
if (sl->Offset != nullptr) if (sl->Offset != nullptr)
{ {
auto o1 = static_cast<ZCC_Expression *>(Simplify(sl->Offset, &c->Type()->Symbols)); auto o1 = static_cast<ZCC_Expression *>(Simplify(sl->Offset, &c->Type()->Symbols, true));
auto o2 = static_cast<ZCC_Expression *>(Simplify(static_cast<ZCC_Expression *>(o1->SiblingNext), &c->Type()->Symbols)); auto o2 = static_cast<ZCC_Expression *>(Simplify(static_cast<ZCC_Expression *>(o1->SiblingNext), &c->Type()->Symbols, true));
if (o1->Operation != PEX_ConstValue || o2->Operation != PEX_ConstValue) if (o1->Operation != PEX_ConstValue || o2->Operation != PEX_ConstValue)
{ {
@ -2201,7 +2213,7 @@ void ZCCCompiler::CompileStates()
statename.Truncate((long)statename.Len() - 1); // remove the last '.' in the label name statename.Truncate((long)statename.Len() - 1); // remove the last '.' in the label name
if (sg->Offset != nullptr) if (sg->Offset != nullptr)
{ {
auto ofs = Simplify(sg->Offset, &c->Type()->Symbols); auto ofs = Simplify(sg->Offset, &c->Type()->Symbols, true);
if (ofs->Operation != PEX_ConstValue) if (ofs->Operation != PEX_ConstValue)
{ {
Error(sg, "Constant offset expected for GOTO"); Error(sg, "Constant offset expected for GOTO");

View file

@ -111,13 +111,15 @@ private:
void CompileStates(); void CompileStates();
FxExpression *SetupActionFunction(PClassActor *cls, ZCC_TreeNode *sl); FxExpression *SetupActionFunction(PClassActor *cls, ZCC_TreeNode *sl);
bool SimplifyingConstant;
TArray<ZCC_ConstantDef *> Constants; TArray<ZCC_ConstantDef *> Constants;
TArray<ZCC_StructWork *> Structs; TArray<ZCC_StructWork *> Structs;
TArray<ZCC_ClassWork *> Classes; TArray<ZCC_ClassWork *> Classes;
PSymbolTreeNode *AddTreeNode(FName name, ZCC_TreeNode *node, PSymbolTable *treenodes, bool searchparents = false); PSymbolTreeNode *AddTreeNode(FName name, ZCC_TreeNode *node, PSymbolTable *treenodes, bool searchparents = false);
ZCC_Expression *Simplify(ZCC_Expression *root, PSymbolTable *Symbols); ZCC_Expression *Simplify(ZCC_Expression *root, PSymbolTable *Symbols, bool wantconstant);
ZCC_Expression *DoSimplify(ZCC_Expression *root, PSymbolTable *Symbols);
ZCC_Expression *SimplifyUnary(ZCC_ExprUnary *unary, PSymbolTable *Symbols); ZCC_Expression *SimplifyUnary(ZCC_ExprUnary *unary, PSymbolTable *Symbols);
ZCC_Expression *SimplifyBinary(ZCC_ExprBinary *binary, PSymbolTable *Symbols); ZCC_Expression *SimplifyBinary(ZCC_ExprBinary *binary, PSymbolTable *Symbols);
ZCC_Expression *SimplifyMemberAccess(ZCC_ExprMemberAccess *dotop, PSymbolTable *Symbols); ZCC_Expression *SimplifyMemberAccess(ZCC_ExprMemberAccess *dotop, PSymbolTable *Symbols);