- create class types from the AST.

This is the first thing the compiler has to do to get access to the class's symbol table. Of course at this point the final size of a class is not known yet so these are currently all treated as tentative.
This commit is contained in:
Christoph Oelckers 2016-10-08 11:54:33 +02:00
parent fff428c71d
commit b71e8d09ed
5 changed files with 149 additions and 6 deletions

View file

@ -175,6 +175,7 @@ class_head(X) ::= CLASS(T) IDENTIFIER(A) class_ancestry(B) class_flags(C).
head->ParentName = B;
head->Flags = C.Flags;
head->Replaces = C.Replaces;
head->Type = nullptr;
X = head;
}
@ -184,8 +185,8 @@ class_ancestry(X) ::= COLON dottable_id(A). { X = A; /*X-overwrites-A*/ }
%type class_flags{ClassFlagsBlock}
class_flags(X) ::= . { X.Flags = 0; X.Replaces = NULL; }
class_flags(X) ::= class_flags(A) ABSTRACT. { X.Flags = A.Flags | 0/*FIXME*/; X.Replaces = A.Replaces; }
class_flags(X) ::= class_flags(A) NATIVE. { X.Flags = A.Flags | 0/*FIXME*/; X.Replaces = A.Replaces; }
class_flags(X) ::= class_flags(A) ABSTRACT. { X.Flags = A.Flags | ZCC_Abstract; X.Replaces = A.Replaces; }
class_flags(X) ::= class_flags(A) NATIVE. { X.Flags = A.Flags | ZCC_Native; X.Replaces = A.Replaces; }
class_flags(X) ::= class_flags(A) REPLACES dottable_id(B). { X.Flags = A.Flags; X.Replaces = B; }
/*----- Dottable Identifier -----*/

View file

@ -181,10 +181,128 @@ void ZCCCompiler::MessageV(ZCC_TreeNode *node, const char *txtcolor, const char
int ZCCCompiler::Compile()
{
CreateClasses();
CompileConstants(Constants);
return ErrorCount;
}
//==========================================================================
//
// ZCCCompiler :: CreateClassTypes
//
// Creates a PClass for every class so that we get access to the symbol table
// These will be created with unknown size because for that we need to
// process all fields first, but to do that we need the PClass and some
// other info depending on the PClass.
//
//==========================================================================
void ZCCCompiler::CreateClasses()
{
auto OrigClasses = std::move(Classes);
Classes.Clear();
bool donesomething = true;
while (donesomething)
{
for (unsigned i=0;i<OrigClasses.Size();i++)
{
donesomething = false;
auto c = OrigClasses[i];
// Check if we got the parent already defined.
PClass *parent;
if (c->ParentName != nullptr && c->ParentName->SiblingNext == c->ParentName) parent = PClass::FindClass(c->ParentName->Id);
else if (c->ParentName == nullptr) parent = RUNTIME_CLASS(DObject);
else
{
// The parent is a dotted name which the type system currently does not handle.
// Once it does this needs to be implemented here.
auto p = c->ParentName;
FString build;
do
{
if (build.IsNotEmpty()) build += '.';
build += FName(p->Id);
p = static_cast<decltype(p)>(p->SiblingNext);
} while (p != c->ParentName);
Error(c, "Qualified name '%s' for base class not supported in '%s'", build.GetChars(), FName(c->NodeName).GetChars());
parent = RUNTIME_CLASS(DObject);
}
if (parent != nullptr)
{
// The parent exists, we may create a type for this class
if (c->Flags & ZCC_Native)
{
// If this is a native class, its own type must also already exist.
auto me = PClass::FindClass(c->NodeName);
if (me == nullptr)
{
Error(c, "Unknown native class %s", FName(c->NodeName).GetChars());
me = parent->FindClassTentative(c->NodeName);
}
else
{
DPrintf(DMSG_SPAMMY, "Registered %s as native with parent %s\n", me->TypeName.GetChars(), parent->TypeName.GetChars());
}
c->Type = me;
}
else
{
auto me = PClass::FindClass(c->NodeName);
if (me != nullptr)
{
Error(c, "Redefining class %s", FName(c->NodeName).GetChars());
}
else
{
me = parent->FindClassTentative(c->NodeName);
DPrintf(DMSG_SPAMMY, "Created %s with parent %s\n", me->TypeName.GetChars(), parent->TypeName.GetChars());
}
c->Type = me;
}
Classes.Push(c);
OrigClasses.Delete(i);
i--;
donesomething = true;
}
else
{
// No base class found. Now check if something in the unprocessed classes matches.
// If not, print an error. If something is found let's retry again in the next iteration.
bool found = false;
for (auto d : OrigClasses)
{
if (d->NodeName == c->ParentName->Id)
{
found = true;
break;
}
}
if (!found)
{
Error(c, "Class %s has unknown base class %s", FName(c->NodeName).GetChars(), FName(c->ParentName->Id).GetChars());
// create a placeholder so that the compiler can continue looking for errors.
c->Type = RUNTIME_CLASS(DObject)->FindClassTentative(c->NodeName);
Classes.Push(c);
OrigClasses.Delete(i);
donesomething = true;
}
}
}
}
// What's left refers to some other class in the list but could not be resolved.
// This normally means a circular reference.
for (auto c : OrigClasses)
{
Error(c, "Class %s has circular inheritance", FName(c->NodeName).GetChars());
c->Type = RUNTIME_CLASS(DObject)->FindClassTentative(c->NodeName);
Classes.Push(c);
}
}
//==========================================================================
//
// ZCCCompiler :: CompileConstants

View file

@ -8,6 +8,7 @@ public:
int Compile();
private:
void CreateClasses();
void CompileConstants(const TArray<ZCC_ConstantDef *> &defs);
PSymbolConst *CompileConstant(ZCC_ConstantDef *def);

View file

@ -318,8 +318,8 @@ static void DoParse(int lumpnum)
ZCCParse(parser, 0, value, &state);
ZCCParseFree(parser, free);
ZCCCompiler cc(state, NULL, GlobalSymbols);
cc.Compile();
{
// Make a dump of the AST before running the compiler for diagnostic purposes.
#ifdef _DEBUG
if (f != NULL)
{
@ -328,7 +328,28 @@ static void DoParse(int lumpnum)
FString ast = ZCC_PrintAST(state.TopNode);
FString filename = Wads.GetLumpFullName(lumpnum);
FString astfile = ExtractFileBase(filename, false);
astfile << ".ast";
astfile << "-before.ast";
f = fopen(astfile, "w");
if (f != NULL)
{
fputs(ast.GetChars(), f);
fclose(f);
}
#endif
}
ZCCCompiler cc(state, NULL, GlobalSymbols);
cc.Compile();
// ... and another one afterward so we can see what the compiler does with the data.
#ifdef _DEBUG
if (f != NULL)
{
fclose(f);
}
FString ast = ZCC_PrintAST(state.TopNode);
FString filename = Wads.GetLumpFullName(lumpnum);
FString astfile = ExtractFileBase(filename, false);
astfile << "-after.ast";
f = fopen(astfile, "w");
if (f != NULL)
{

View file

@ -16,7 +16,7 @@ struct ZCCToken
ENamedName Name() { return ENamedName(Int); }
};
// Variable / Function modifiers
// Variable / Function / Class modifiers
enum
{
ZCC_Native = 1 << 0,
@ -30,6 +30,7 @@ enum
ZCC_Deprecated = 1 << 8,
ZCC_ReadOnly = 1 << 9,
ZCC_FuncConst = 1 << 10,
ZCC_Abstract = 1 << 11,
};
// Function parameter modifiers
@ -185,6 +186,7 @@ struct ZCC_Class : ZCC_NamedNode
ZCC_Identifier *Replaces;
VM_UWORD Flags;
ZCC_TreeNode *Body;
PClass *Type;
};
struct ZCC_Struct : ZCC_NamedNode