From b71e8d09edd031f8b8a42c985f1610ae539abef2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 8 Oct 2016 11:54:33 +0200 Subject: [PATCH] - 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. --- src/zscript/zcc-parse.lemon | 5 +- src/zscript/zcc_compile.cpp | 118 ++++++++++++++++++++++++++++++++++++ src/zscript/zcc_compile.h | 1 + src/zscript/zcc_parser.cpp | 27 ++++++++- src/zscript/zcc_parser.h | 4 +- 5 files changed, 149 insertions(+), 6 deletions(-) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index cd2ed8efe..6d22f9ea4 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -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 -----*/ diff --git a/src/zscript/zcc_compile.cpp b/src/zscript/zcc_compile.cpp index e6d2e6d96..68261635f 100644 --- a/src/zscript/zcc_compile.cpp +++ b/src/zscript/zcc_compile.cpp @@ -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;iParentName != 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(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 diff --git a/src/zscript/zcc_compile.h b/src/zscript/zcc_compile.h index d034464b7..24497acd9 100644 --- a/src/zscript/zcc_compile.h +++ b/src/zscript/zcc_compile.h @@ -8,6 +8,7 @@ public: int Compile(); private: + void CreateClasses(); void CompileConstants(const TArray &defs); PSymbolConst *CompileConstant(ZCC_ConstantDef *def); diff --git a/src/zscript/zcc_parser.cpp b/src/zscript/zcc_parser.cpp index ed41253e1..3a34abe07 100644 --- a/src/zscript/zcc_parser.cpp +++ b/src/zscript/zcc_parser.cpp @@ -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) { diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index 507f80b9e..8b82b7eae 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -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