Value IdentExpr::Evaluate(SymbolTable* scope, EvalContext& context, bool asbool) { /// Scope override; must do this for every expression that might contain an identifier if(this->scope != NULL) scope = this->scope; //context.file = this->file; //context.line = this->linenumber; // To evaluate an identifier expression: // First, we have to look up the symbol and check the type of its value. // If it's a constant, we just evaluate the constant (provided there are no // parameters given; if there are parameters, we should report an error.) // If it's a command, we need to: // - bind each argument expression to the corresponding symbol in the commands // parameter list. // - invoke the command. Module* module = context.module; SymbolTable* lookupScope = scope; // If the ident expr's "file" field is not empty, we'll look it up in a different module if(!file.empty()) { Module* mod = module->GetSiblingContext(file); if(!mod) { Error("reference to nonexistent module '" + file + "'"); return Value::Null; } lookupScope = mod->GetRootTable(); } Value found = lookupScope->Lookup(name); if(found != Value::Undefined) { // In most cases, we just return the value. if(found.GetType() != Type::Macro) { // However, evaluated vars are not importable. if(lookupScope != scope) { Error("cannot access local variable declaration '" + name + "' in module '" + file + "'"); return Value::Null; } return found; } Node* node = found.GetNode(); Value result; if(node->GetType() == conststmt) { if(hasparens) { Error("'" + GetFullName() + "' refers to a constant; cannot use parentheses"); return Value(); } result = dynamic_cast<ConstDef*>(node)->EvaluateExpr(scope, context, asbool); } else if(node->GetType() == commandstmt) { for(unsigned int i = 0; i < args.size(); ++i) args[i]->scope = scope; CommandDef* cmd = dynamic_cast<CommandDef*>(found.GetNode()); if(cmd->GetArgCount() != args.size()) Error("incorrect number of parameters to command '" + GetFullName() + "'"); else result = cmd->Invoke(context, args); } else if(node->GetType() == ambiguousid) { AmbiguousID* ambig = dynamic_cast<AmbiguousID*>(found.GetNode()); Error(ambig->ToString("")); result = Value::Null; } else if(node->IsExpression()) { result = dynamic_cast<Expression*>(node)->Evaluate(scope, context, asbool); } else { Error("invalid type"); } return result; } // Didn't find it in the symbol table, check the jumps table Anchor* foundanchor = lookupScope->LookupAnchor(name); if(foundanchor) { if(hasparens) { Error("'" + GetFullName() + "' refers to a label; cannot use parentheses"); return Value(); } String* val = new String(); val->Long(foundanchor->GetTarget()); // The targeted label might not have its address computed yet, so we register a // reference to the target label (unless refs are forbidden by the context) if(!context.norefs) val->AddReference(val->GetPos()-4, foundanchor); return Value(val); } Error("use of undefined identifier '" + GetFullName() + "'"); return Value(); }