From 63846134877758ca0c1ba699d2e0674a4d7a0223 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 25 Oct 2013 22:01:18 -0500 Subject: [PATCH] Allow using constants in other constants before their definitions. - Something like this is now valid: const foo = bar + 10; const bar = 1000; --- src/zscript/zcc_compile.cpp | 96 ++++++++++++++++++++++++++++++++----- src/zscript/zcc_compile.h | 3 ++ src/zscript/zcc_errors.h | 2 + 3 files changed, 89 insertions(+), 12 deletions(-) diff --git a/src/zscript/zcc_compile.cpp b/src/zscript/zcc_compile.cpp index 385db01e32..61f96a90ce 100644 --- a/src/zscript/zcc_compile.cpp +++ b/src/zscript/zcc_compile.cpp @@ -10,6 +10,8 @@ #include "v_text.h" #include "gdtoa.h" +#define DEFINING_CONST ((PSymbolConst *)(void *)1) + //========================================================================== // // ZCCCompiler Constructor @@ -27,12 +29,33 @@ ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols) { switch (node->NodeType) { - case AST_Class: Classes.Push(static_cast(node)); break; - case AST_Struct: Structs.Push(static_cast(node)); break; + case AST_Class: +// if (AddNamedNode(static_cast(node)->ClassName, node)) + { + Classes.Push(static_cast(node)); + } + break; + + case AST_Struct: + if (AddNamedNode(static_cast(node)->StructName, node)) + { + Structs.Push(static_cast(node)); + } + break; + case AST_Enum: break; case AST_EnumTerminator:break; - case AST_ConstantDef: Constants.Push(static_cast(node)); break; - default: assert(0 && "Unhandled AST node type"); break; + + case AST_ConstantDef: + if (AddNamedNode(static_cast(node)->Name, node)) + { + Constants.Push(static_cast(node)); + } + break; + + default: + assert(0 && "Unhandled AST node type"); + break; } node = node->SiblingNext; } @@ -40,6 +63,31 @@ ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols) } } +//========================================================================== +// +// ZCCCompiler :: AddNamedNode +// +// Keeps track of definition nodes by their names. Ensures that all names +// in this scope are unique. +// +//========================================================================== + +bool ZCCCompiler::AddNamedNode(FName name, ZCC_TreeNode *node) +{ + ZCC_TreeNode **check = NamedNodes.CheckKey(name); + if (check != NULL && *check != NULL) + { + Message(node, ERR_symbol_redefinition, "Attempt to redefine '%s'", name.GetChars()); + Message(*check, ERR_original_definition, " Original definition is here"); + return false; + } + else + { + NamedNodes.Insert(name, node); + return true; + } +} + //========================================================================== // // ZCCCompiler :: Message @@ -104,11 +152,7 @@ void ZCCCompiler::CompileConstants() ZCC_ConstantDef *def = Constants[i]; if (def->Symbol == NULL) { - PSymbolConst *sym = CompileConstant(def); - if (NULL == Symbols.AddSymbol(sym)) - { - Message(Constants[i], ERR_symbol_redefinition, "Redefinition of symbol '%s'", FName(def->Name).GetChars()); - } + CompileConstant(def); } } } @@ -127,7 +171,7 @@ PSymbolConst *ZCCCompiler::CompileConstant(ZCC_ConstantDef *def) { assert(def->Symbol == NULL); - def->Symbol = (PSymbolConst *)(void *)1; // mark as being defined (avoid recursion) + def->Symbol = DEFINING_CONST; // avoid recursion ZCC_Expression *val = Simplify(def->Value); def->Value = val; PSymbolConst *sym = NULL; @@ -161,6 +205,8 @@ PSymbolConst *ZCCCompiler::CompileConstant(ZCC_ConstantDef *def) sym = new PSymbolConstNumeric(def->Name, TypeError, 0); } def->Symbol = sym; + PSymbol *addsym = Symbols.AddSymbol(sym); + assert(NULL != addsym && "Symbol was redefined (but we shouldn't have even had the chance to do so)"); return sym; } @@ -347,7 +393,28 @@ ZCC_Expression *ZCCCompiler::IdentifyIdentifier(ZCC_ExprID *idnode) } } else - { + { // Check nodes that haven't had symbols created for them yet. + ZCC_TreeNode **node = NamedNodes.CheckKey(idnode->Identifier); + if (node != NULL && *node != NULL) + { + if ((*node)->NodeType == AST_ConstantDef) + { + ZCC_ConstantDef *def = static_cast(*node); + PSymbolConst *sym = def->Symbol; + + if (sym == DEFINING_CONST) + { + Message(idnode, ERR_recursive_definition, "Definition of '%s' is infinitely recursive", FName(idnode->Identifier).GetChars()); + sym = NULL; + } + else + { + assert(sym == NULL); + sym = CompileConstant(def); + } + return NodeFromSymbolConst(sym, idnode); + } + } } // Identifier didn't refer to anything good, so type error it. idnode->Type = TypeError; @@ -368,7 +435,12 @@ ZCC_ExprConstant *ZCCCompiler::NodeFromSymbolConst(PSymbolConst *sym, ZCC_ExprID { ZCC_ExprConstant *val = static_cast(AST.InitNode(sizeof(*val), AST_ExprConstant, idnode)); val->Operation = PEX_ConstValue; - if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConstString))) + if (sym == NULL) + { + val->Type = TypeError; + val->IntVal = 0; + } + else if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConstString))) { val->StringVal = AST.Strings.Alloc(static_cast(sym)->Str); val->Type = TypeString; diff --git a/src/zscript/zcc_compile.h b/src/zscript/zcc_compile.h index 78632e444c..69311cdee7 100644 --- a/src/zscript/zcc_compile.h +++ b/src/zscript/zcc_compile.h @@ -16,6 +16,9 @@ private: TArray Constants; TArray Structs; TArray Classes; + TMap NamedNodes; + + bool AddNamedNode(FName name, ZCC_TreeNode *node); ZCC_Expression *Simplify(ZCC_Expression *root); ZCC_Expression *SimplifyUnary(ZCC_ExprUnary *unary); diff --git a/src/zscript/zcc_errors.h b/src/zscript/zcc_errors.h index bfb617b633..4b492d02be 100644 --- a/src/zscript/zcc_errors.h +++ b/src/zscript/zcc_errors.h @@ -5,4 +5,6 @@ enum EZCCError ERR_const_def_not_constant = 20000 | ZCCERR_ERROR, ERR_bad_const_def_type = 20001 | ZCCERR_ERROR, ERR_symbol_redefinition = 20002 | ZCCERR_ERROR, + ERR_original_definition = 20003 | ZCCERR_ERROR, + ERR_recursive_definition = 20004 | ZCCERR_ERROR, };