diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index b8a5cbcf9..609ec1721 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2711,6 +2711,7 @@ END_POINTERS IMPLEMENT_POINTY_CLASS(PSymbolVMFunction) DECLARE_POINTER(Function) END_POINTERS +IMPLEMENT_CLASS(PSymbolTreeNode) //========================================================================== // @@ -2773,6 +2774,22 @@ PSymbol *PSymbolTable::FindSymbol (FName symname, bool searchparents) const return value != NULL ? *value : NULL; } +PSymbol *PSymbolTable::FindSymbolInTable(FName symname, PSymbolTable *&symtable) +{ + PSymbol * const *value = Symbols.CheckKey(symname); + if (value == NULL) + { + if (ParentSymbolTable != NULL) + { + return ParentSymbolTable->FindSymbolInTable(symname, symtable); + } + symtable = NULL; + return NULL; + } + symtable = this; + return *value; +} + PSymbol *PSymbolTable::AddSymbol (PSymbol *sym) { // Symbols that already exist are not inserted. @@ -2783,3 +2800,19 @@ PSymbol *PSymbolTable::AddSymbol (PSymbol *sym) Symbols.Insert(sym->SymbolName, sym); return sym; } + +PSymbol *PSymbolTable::ReplaceSymbol(PSymbol *newsym) +{ + // If a symbol with a matching name exists, take its place and return it. + PSymbol **symslot = Symbols.CheckKey(newsym->SymbolName); + if (symslot != NULL) + { + PSymbol *oldsym = *symslot; + *symslot = newsym; + return oldsym; + } + // Else, just insert normally and return NULL since there was no + // symbol to replace. + Symbols.Insert(newsym->SymbolName, newsym); + return NULL; +} diff --git a/src/dobjtype.h b/src/dobjtype.h index 70c5d850d..b482efe45 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -67,6 +67,18 @@ public: PSymbolType() : PSymbol(NAME_None) {} }; +// A symbol for a compiler tree node ---------------------------------------- + +class PSymbolTreeNode : public PSymbol +{ + DECLARE_CLASS(PSymbolTreeNode, PSymbol); +public: + struct ZCC_NamedNode *Node; + + PSymbolTreeNode(FName name, struct ZCC_NamedNode *node) : PSymbol(name), Node(node) {} + PSymbolTreeNode() : PSymbol(NAME_None) {} +}; + // A symbol table ----------------------------------------------------------- struct PSymbolTable @@ -85,11 +97,19 @@ struct PSymbolTable // as well. PSymbol *FindSymbol (FName symname, bool searchparents) const; + // Like FindSymbol with searchparents set true, but also returns the + // specific symbol table the symbol was found in. + PSymbol *FindSymbolInTable(FName symname, PSymbolTable *&symtable); + // Places the symbol in the table and returns a pointer to it or NULL if // a symbol with the same name is already in the table. This symbol is // not copied and will be freed when the symbol table is destroyed. PSymbol *AddSymbol (PSymbol *sym); + // Similar to AddSymbol but always succeeds. Returns the symbol that used + // to be in the table with this name, if any. + PSymbol *ReplaceSymbol(PSymbol *sym); + // Frees all symbols from this table. void ReleaseSymbols(); diff --git a/src/zscript/ast.cpp b/src/zscript/ast.cpp index a59a656af..a68b1c69f 100644 --- a/src/zscript/ast.cpp +++ b/src/zscript/ast.cpp @@ -281,7 +281,7 @@ static void PrintClass(FLispString &out, ZCC_TreeNode *node) ZCC_Class *cnode = (ZCC_Class *)node; out.Break(); out.Open("class"); - out.AddName(cnode->ClassName); + out.AddName(cnode->NodeName); PrintNodes(out, cnode->ParentName); PrintNodes(out, cnode->Replaces); out.AddHex(cnode->Flags); @@ -294,7 +294,7 @@ static void PrintStruct(FLispString &out, ZCC_TreeNode *node) ZCC_Struct *snode = (ZCC_Struct *)node; out.Break(); out.Open("struct"); - out.AddName(snode->StructName); + out.AddName(snode->NodeName); PrintNodes(out, snode->Body, false, true); out.Close(); } @@ -304,7 +304,7 @@ static void PrintEnum(FLispString &out, ZCC_TreeNode *node) ZCC_Enum *enode = (ZCC_Enum *)node; out.Break(); out.Open("enum"); - out.AddName(enode->EnumName); + out.AddName(enode->NodeName); PrintBuiltInType(out, enode->EnumType); out.Add(enode->Elements == NULL ? "nil" : "...", 3); out.Close(); @@ -733,7 +733,7 @@ static void PrintConstantDef(FLispString &out, ZCC_TreeNode *node) ZCC_ConstantDef *dnode = (ZCC_ConstantDef *)node; out.Break(); out.Open("constant-def"); - out.AddName(dnode->Name); + out.AddName(dnode->NodeName); PrintNodes(out, dnode->Value, false); out.Close(); } diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index c42e0818b..69feacdc7 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -174,7 +174,7 @@ class_definition(X) ::= class_head(A) class_body(B). class_head(X) ::= CLASS(T) IDENTIFIER(A) class_ancestry(B) class_flags(C). { NEW_AST_NODE(Class,head,T); - head->ClassName = A.Name(); + head->NodeName = A.Name(); head->ParentName = B; head->Flags = C.Flags; head->Replaces = C.Replaces; @@ -248,7 +248,7 @@ class_member(X) ::= const_def(A). { X = A; } struct_def(X) ::= STRUCT(T) IDENTIFIER(A) LBRACE opt_struct_body(B) RBRACE opt_semicolon. { NEW_AST_NODE(Struct,def,T); - def->StructName = A.Name(); + def->NodeName = A.Name(); def->Body = B; X = def; } @@ -269,7 +269,7 @@ struct_member(X) ::= const_def(A). { X = A; } const_def(X) ::= CONST(T) IDENTIFIER(A) EQ expr(B) SEMICOLON. { NEW_AST_NODE(ConstantDef,def,T); - def->Name = A.Name(); + def->NodeName = A.Name(); def->Value = B; def->Symbol = NULL; X = def; @@ -286,7 +286,7 @@ const_def(X) ::= CONST(T) IDENTIFIER(A) EQ expr(B) SEMICOLON. enum_def(X) ::= ENUM(T) IDENTIFIER(A) enum_type(B) LBRACE opt_enum_list(C) RBRACE(U) opt_semicolon. { NEW_AST_NODE(Enum,def,T); - def->EnumName = A.Name(); + def->NodeName = A.Name(); def->EnumType = (EZCCBuiltinType)B.Int; def->Elements = C; @@ -324,7 +324,7 @@ enum_def(X) ::= ENUM(T) IDENTIFIER(A) enum_type(B) LBRACE opt_enum_list(C) RBRAC NEW_INTCONST_NODE(one, TypeSInt32, 1, T); NEW_AST_NODE(ExprID, label, node); label->Operation = PEX_ID; - label->Identifier = prev->Name; + label->Identifier = prev->NodeName; label->Type = NULL; BINARY_EXPR(label, one, PEX_Add); @@ -355,7 +355,7 @@ opt_enum_list(X) ::= enum_list(A) opt_comma. { X = A; } enumerator(X) ::= IDENTIFIER(A). { NEW_AST_NODE(ConstantDef,node,A); - node->Name = A.Name(); + node->NodeName = A.Name(); node->Value = NULL; node->Symbol = NULL; X = node; @@ -363,7 +363,7 @@ enumerator(X) ::= IDENTIFIER(A). enumerator(X) ::= IDENTIFIER(A) EQ expr(B). /* Expression must be constant. */ { NEW_AST_NODE(ConstantDef,node,A); - node->Name = A.Name(); + node->NodeName = A.Name(); node->Value = B; node->Symbol = NULL; X = node; diff --git a/src/zscript/zcc_compile.cpp b/src/zscript/zcc_compile.cpp index 5a3276a07..037e4fa42 100644 --- a/src/zscript/zcc_compile.cpp +++ b/src/zscript/zcc_compile.cpp @@ -19,7 +19,7 @@ //========================================================================== ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols) -: Outer(_outer), Symbols(_symbols), AST(ast), ErrorCount(0), WarnCount(0) +: Outer(_outer), Symbols(&_symbols), AST(ast), ErrorCount(0), WarnCount(0) { // Group top-level nodes by type if (ast.TopNode != NULL) @@ -30,29 +30,22 @@ ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols) switch (node->NodeType) { 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)) + case AST_ConstantDef: + if (AddNamedNode(static_cast(node))) { - Structs.Push(static_cast(node)); + switch (node->NodeType) + { + case AST_Class: Classes.Push(static_cast(node)); break; + case AST_Struct: Structs.Push(static_cast(node)); break; + case AST_ConstantDef: Constants.Push(static_cast(node)); break; + } } break; case AST_Enum: break; case AST_EnumTerminator: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; @@ -72,55 +65,76 @@ ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols) // //========================================================================== -bool ZCCCompiler::AddNamedNode(FName name, ZCC_TreeNode *node) +bool ZCCCompiler::AddNamedNode(ZCC_NamedNode *node) { - ZCC_TreeNode **check = NamedNodes.CheckKey(name); - if (check != NULL && *check != NULL) + FName name = node->NodeName; + PSymbol *check = Symbols->FindSymbol(name, false); + if (check != NULL) { - Message(node, ERR_symbol_redefinition, "Attempt to redefine '%s'", name.GetChars()); - Message(*check, ERR_original_definition, " Original definition is here"); + assert(check->IsA(RUNTIME_CLASS(PSymbolTreeNode))); + Error(node, "Attempt to redefine '%s'", name.GetChars()); + Error(static_cast(check)->Node, " Original definition is here"); return false; } else { - NamedNodes.Insert(name, node); + Symbols->AddSymbol(new PSymbolTreeNode(name, node)); return true; } } //========================================================================== // -// ZCCCompiler :: Message +// ZCCCompiler :: Warn // -// Prints a warning or error message, and increments the appropriate -// counter. +// Prints a warning message, and increments WarnCount. // //========================================================================== -void ZCCCompiler::Message(ZCC_TreeNode *node, EZCCError errnum, const char *msg, ...) +void ZCCCompiler::Warn(ZCC_TreeNode *node, const char *msg, ...) +{ + va_list argptr; + va_start(argptr, msg); + MessageV(node, TEXTCOLOR_ORANGE, msg, argptr); + va_end(argptr); + + WarnCount++; +} + +//========================================================================== +// +// ZCCCompiler :: Error +// +// Prints an error message, and increments ErrorCount. +// +//========================================================================== + +void ZCCCompiler::Error(ZCC_TreeNode *node, const char *msg, ...) +{ + va_list argptr; + va_start(argptr, msg); + MessageV(node, TEXTCOLOR_RED, msg, argptr); + va_end(argptr); + + ErrorCount++; +} + +//========================================================================== +// +// ZCCCompiler :: MessageV +// +// Prints a message, annotated with the source location for the tree node. +// +//========================================================================== + +void ZCCCompiler::MessageV(ZCC_TreeNode *node, const char *txtcolor, const char *msg, va_list argptr) { FString composed; - composed.Format("%s%s, line %d: ", - errnum & ZCCERR_ERROR ? TEXTCOLOR_RED : TEXTCOLOR_ORANGE, - node->SourceName->GetChars(), node->SourceLoc); - - va_list argptr; - va_start(argptr, msg); + composed.Format("%s%s, line %d: ", txtcolor, node->SourceName->GetChars(), node->SourceLoc); composed.VAppendFormat(msg, argptr); - va_end(argptr); - composed += '\n'; PrintString(PRINT_HIGH, composed); - - if (errnum & ZCCERR_ERROR) - { - ErrorCount++; - } - else - { - WarnCount++; - } } //========================================================================== @@ -133,7 +147,7 @@ void ZCCCompiler::Message(ZCC_TreeNode *node, EZCCError errnum, const char *msg, int ZCCCompiler::Compile() { - CompileConstants(); + CompileConstants(Constants); return ErrorCount; } @@ -145,14 +159,14 @@ int ZCCCompiler::Compile() // //========================================================================== -void ZCCCompiler::CompileConstants() +void ZCCCompiler::CompileConstants(const TArray &defs) { - for (unsigned i = 0; i < Constants.Size(); ++i) + for (unsigned i = 0; i < defs.Size(); ++i) { - ZCC_ConstantDef *def = Constants[i]; + ZCC_ConstantDef *def = defs[i]; if (def->Symbol == NULL) { - CompileConstant(def); + PSymbolConst *sym = CompileConstant(def); } } } @@ -180,33 +194,32 @@ PSymbolConst *ZCCCompiler::CompileConstant(ZCC_ConstantDef *def) ZCC_ExprConstant *cval = static_cast(val); if (cval->Type == TypeString) { - sym = new PSymbolConstString(def->Name, *(cval->StringVal)); + sym = new PSymbolConstString(def->NodeName, *(cval->StringVal)); } else if (cval->Type->IsA(RUNTIME_CLASS(PInt))) { - sym = new PSymbolConstNumeric(def->Name, cval->Type, cval->IntVal); + sym = new PSymbolConstNumeric(def->NodeName, cval->Type, cval->IntVal); } else if (cval->Type->IsA(RUNTIME_CLASS(PFloat))) { - sym = new PSymbolConstNumeric(def->Name, cval->Type, cval->DoubleVal); + sym = new PSymbolConstNumeric(def->NodeName, cval->Type, cval->DoubleVal); } else { - Message(def->Value, ERR_bad_const_def_type, "Bad type for constant definiton"); + Error(def->Value, "Bad type for constant definiton"); } } else { - Message(def->Value, ERR_const_def_not_constant, "Constant definition requires a constant value"); + Error(def->Value, "Constant definition requires a constant value"); } if (sym == NULL) { // Create a dummy constant so we don't make any undefined value warnings. - sym = new PSymbolConstNumeric(def->Name, TypeError, 0); + sym = new PSymbolConstNumeric(def->NodeName, 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)"); + Symbols->ReplaceSymbol(sym); return sym; } @@ -307,17 +320,18 @@ ZCC_Expression *ZCCCompiler::SimplifyMemberAccess(ZCC_ExprMemberAccess *dotop) if (dotop->Left->Operation == PEX_TypeRef) { // Type refs can be evaluated now. PType *ref = static_cast(dotop->Left)->RefType; - PSymbol *sym = ref->Symbols.FindSymbol(dotop->Right, true); + PSymbolTable *symtable; + PSymbol *sym = ref->Symbols.FindSymbolInTable(dotop->Right, symtable); if (sym == NULL) { - Message(dotop, ERR_not_a_member, "'%s' is not a valid member", FName(dotop->Right).GetChars()); + Error(dotop, "'%s' is not a valid member", FName(dotop->Right).GetChars()); } else { - ZCC_Expression *expr = NodeFromSymbol(sym, dotop); + ZCC_Expression *expr = NodeFromSymbol(sym, dotop, symtable); if (expr == NULL) { - Message(dotop, ERR_bad_symbol, "Unhandled symbol type encountered"); + Error(dotop, "Unhandled symbol type encountered"); } else { @@ -361,7 +375,7 @@ ZCC_Expression *ZCCCompiler::SimplifyFunctionCall(ZCC_ExprFuncCall *callop) { if (parmcount != 1) { - Message(callop, ERR_cast_needs_1_parm, "Type cast requires one parameter"); + Error(callop, "Type cast requires one parameter"); callop->ToErrorNode(); } else @@ -371,8 +385,8 @@ ZCC_Expression *ZCCCompiler::SimplifyFunctionCall(ZCC_ExprFuncCall *callop) int routelen = parm->Value->Type->FindConversion(dest, route, countof(route)); if (routelen < 0) { - // FIXME: Need real type names - Message(callop, ERR_cast_not_possible, "Cannot convert type 1 to type 2"); + ///FIXME: Need real type names + Error(callop, "Cannot convert type 1 to type 2"); callop->ToErrorNode(); } else @@ -483,53 +497,79 @@ ZCC_Expression *ZCCCompiler::AddCastNode(PType *type, ZCC_Expression *expr) ZCC_Expression *ZCCCompiler::IdentifyIdentifier(ZCC_ExprID *idnode) { - // First things first: Check the symbol table. - PSymbol *sym; - if (NULL != (sym = Symbols.FindSymbol(idnode->Identifier, true))) + // Check the symbol table for the identifier. + PSymbolTable *table; + PSymbol *sym = Symbols->FindSymbolInTable(idnode->Identifier, table); + if (sym != NULL) { - ZCC_Expression *node = NodeFromSymbol(sym, idnode); + ZCC_Expression *node = NodeFromSymbol(sym, idnode, table); if (node != NULL) { return node; } } 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); - } - } + { + Error(idnode, "Unknown identifier '%s'", FName(idnode->Identifier).GetChars()); } // Identifier didn't refer to anything good, so type error it. idnode->ToErrorNode(); return idnode; } +//========================================================================== +// +// ZCCCompiler :: CompileNode +// +//========================================================================== + +PSymbol *ZCCCompiler::CompileNode(ZCC_NamedNode *node) +{ + assert(node != NULL); + if (node->NodeType == AST_ConstantDef) + { + ZCC_ConstantDef *def = static_cast(node); + PSymbolConst *sym = def->Symbol; + + if (sym == DEFINING_CONST) + { + Error(node, "Definition of '%s' is infinitely recursive", FName(node->NodeName).GetChars()); + sym = NULL; + } + else + { + assert(sym == NULL); + sym = CompileConstant(def); + } + return sym; + } + else if (node->NodeType == AST_Struct) + { + + } + return NULL; +} + //========================================================================== // // ZCCCompiler :: NodeFromSymbol // //========================================================================== -ZCC_Expression *ZCCCompiler::NodeFromSymbol(PSymbol *sym, ZCC_Expression *source) +ZCC_Expression *ZCCCompiler::NodeFromSymbol(PSymbol *sym, ZCC_Expression *source, PSymbolTable *table) { + assert(sym != NULL); + if (sym->IsA(RUNTIME_CLASS(PSymbolTreeNode))) + { + PSymbolTable *prevtable = Symbols; + Symbols = table; + sym = CompileNode(static_cast(sym)->Node); + Symbols = prevtable; + if (sym == NULL) + { + return NULL; + } + } if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) { return NodeFromSymbolConst(static_cast(sym), source); diff --git a/src/zscript/zcc_compile.h b/src/zscript/zcc_compile.h index c8933ff5f..7f1f71c93 100644 --- a/src/zscript/zcc_compile.h +++ b/src/zscript/zcc_compile.h @@ -1,8 +1,6 @@ #ifndef ZCC_COMPILE_H #define ZCC_COMPILE_H -#include "zcc_errors.h" - class ZCCCompiler { public: @@ -10,15 +8,14 @@ public: int Compile(); private: - void CompileConstants(); + void CompileConstants(const TArray &defs); PSymbolConst *CompileConstant(ZCC_ConstantDef *def); TArray Constants; TArray Structs; TArray Classes; - TMap NamedNodes; - bool AddNamedNode(FName name, ZCC_TreeNode *node); + bool AddNamedNode(ZCC_NamedNode *node); ZCC_Expression *Simplify(ZCC_Expression *root); ZCC_Expression *SimplifyUnary(ZCC_ExprUnary *unary); @@ -37,14 +34,18 @@ private: ZCC_Expression *AddCastNode(PType *type, ZCC_Expression *expr); ZCC_Expression *IdentifyIdentifier(ZCC_ExprID *idnode); - ZCC_Expression *NodeFromSymbol(PSymbol *sym, ZCC_Expression *source); + ZCC_Expression *NodeFromSymbol(PSymbol *sym, ZCC_Expression *source, PSymbolTable *table); ZCC_ExprConstant *NodeFromSymbolConst(PSymbolConst *sym, ZCC_Expression *idnode); ZCC_ExprTypeRef *NodeFromSymbolType(PSymbolType *sym, ZCC_Expression *idnode); + PSymbol *ZCCCompiler::CompileNode(ZCC_NamedNode *node); - void Message(ZCC_TreeNode *node, EZCCError errnum, const char *msg, ...); + + void Warn(ZCC_TreeNode *node, const char *msg, ...); + void Error(ZCC_TreeNode *node, const char *msg, ...); + void MessageV(ZCC_TreeNode *node, const char *txtcolor, const char *msg, va_list argptr); DObject *Outer; - PSymbolTable &Symbols; + PSymbolTable *Symbols; ZCC_AST &AST; int ErrorCount; int WarnCount; diff --git a/src/zscript/zcc_errors.h b/src/zscript/zcc_errors.h deleted file mode 100644 index cb38a00d5..000000000 --- a/src/zscript/zcc_errors.h +++ /dev/null @@ -1,14 +0,0 @@ -#define ZCCERR_ERROR 0x40000000 - -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, - ERR_not_a_member = 20005 | ZCCERR_ERROR, - ERR_bad_symbol = 20006 | ZCCERR_ERROR, - ERR_cast_needs_1_parm = 20007 | ZCCERR_ERROR, - ERR_cast_not_possible = 20008 | ZCCERR_ERROR, -}; diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index cf51ff765..e74b5263e 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -174,24 +174,26 @@ struct ZCC_Identifier : ZCC_TreeNode ENamedName Id; }; -struct ZCC_Class : ZCC_TreeNode +struct ZCC_NamedNode : ZCC_TreeNode +{ + ENamedName NodeName; +}; + +struct ZCC_Class : ZCC_NamedNode { - ENamedName ClassName; ZCC_Identifier *ParentName; ZCC_Identifier *Replaces; VM_UWORD Flags; ZCC_TreeNode *Body; }; -struct ZCC_Struct : ZCC_TreeNode +struct ZCC_Struct : ZCC_NamedNode { - ENamedName StructName; ZCC_TreeNode *Body; }; -struct ZCC_Enum : ZCC_TreeNode +struct ZCC_Enum : ZCC_NamedNode { - ENamedName EnumName; EZCCBuiltinType EnumType; struct ZCC_ConstantDef *Elements; }; @@ -432,9 +434,8 @@ struct ZCC_FuncParamDecl : ZCC_TreeNode int Flags; }; -struct ZCC_ConstantDef : ZCC_TreeNode +struct ZCC_ConstantDef : ZCC_NamedNode { - ENamedName Name; ZCC_Expression *Value; PSymbolConst *Symbol; };