From 86a7cd12ffefaf63ddc202d0143c7b8fba05390c Mon Sep 17 00:00:00 2001 From: mateuszb Date: Mon, 2 May 2011 18:39:57 +0000 Subject: [PATCH] * checking ERM conditions should work now --- lib/ERMInterpreter.cpp | 370 ++++++++++++++++++++++++++++++++++------- lib/ERMInterpreter.h | 56 +++++-- 2 files changed, 349 insertions(+), 77 deletions(-) diff --git a/lib/ERMInterpreter.cpp b/lib/ERMInterpreter.cpp index 62401654e..fcf34053b 100644 --- a/lib/ERMInterpreter.cpp +++ b/lib/ERMInterpreter.cpp @@ -633,9 +633,11 @@ struct ERMExecEnvironment : ermGlobalEnv(erm), trigEnv(trig), funcVars(funvars) {} - template - T* getVar(std::string toFollow, boost::optional initVal) + IexpValStr getVar(std::string toFollow, boost::optional initVal) { + IexpValStr ret; + ret.type = IexpValStr::WRONGVAL; + int initV; bool hasInit = false; if(initVal.is_initialized()) @@ -650,7 +652,19 @@ struct ERMExecEnvironment endNum = 1; //TODO: support } - T* ret; + if(toFollow.size() == 0) + { + if(hasInit) + { + ret.val.val = initV; + ret.type = IexpValStr::INT; + } + else + throw EIexpProblem("No input to getVar!"); + + return ret; + } + //now we have at least one element in toFollow for(int b=toFollow.size()-1; b>=endNum; --b) { bool retIt = b == endNum+1; //if we should return the value are currently at @@ -674,14 +688,20 @@ struct ERMExecEnvironment if(initV > 0 && initV <= FunctionLocalVars::NUM_FLOATINGS) { if(funcVars) - ret = (T*)funcVars->floats + initV - 1; + { + ret.val.flvar = &funcVars->getFloat(initV); + ret.type = IexpValStr::FLOATVAR; + } else throw EIexpProblem("Function context not available!"); } else if(initV < 0 && initV >= -TriggerLocalVars::EVAR_NUM) { if(trigEnv) - ret = (T*)trigEnv->ermLocalVars.evar - initV + 1; //minus is important! + { + ret.val.flvar = &trigEnv->ermLocalVars.getEvar(initV); + ret.type = IexpValStr::FLOATVAR; + } else throw EIexpProblem("No trigger context available!"); } @@ -697,7 +717,10 @@ struct ERMExecEnvironment else if(cr >= 'f' && cr <= 't') { if(retIt) - ret = &ermGlobalEnv->getQuickVar(cr); + { + ret.val.integervar = &ermGlobalEnv->getQuickVar(cr); + ret.type = IexpValStr::INTVAR; + } else { if(hasInit) @@ -713,15 +736,13 @@ struct ERMExecEnvironment { if(hasInit) { - if(initV > 0 && initV <= ERMEnvironment::NUM_STANDARDS) + if(retIt) { - if(retIt) - ret = ermGlobalEnv->standardVars + initV - 1; - else - initV = ermGlobalEnv->standardVars[initV-1]; + ret.val.integervar = &ermGlobalEnv->getStandardVar(initV); + ret.type = IexpValStr::INTVAR; } else - throw EIexpProblem("standard variable index out of range"); + initV = ermGlobalEnv->getStandardVar(initV); } else throw EIexpProblem("standard variable cannot be used in this context!"); @@ -734,19 +755,17 @@ struct ERMExecEnvironment { if(hasInit) { - if(initV > 0 && initV <= FunctionLocalVars::NUM_PARAMETERS) + if(funcVars) { - if(funcVars) + if(retIt) { - if(retIt) - ret = funcVars->params + initV-1; - else - initV = funcVars->params[initV-1]; + ret.val.integervar = &funcVars->getParam(initV); + ret.type = IexpValStr::INTVAR; } - else throw EIexpProblem("Function parameters cannot be used outside a function!"); + else + initV = funcVars->getParam(initV); } - else - throw EIexpProblem("Parameter number out of range"); + else throw EIexpProblem("Function parameters cannot be used outside a function!"); } else throw EIexpProblem("Specify which function parameter should be used"); @@ -760,9 +779,12 @@ struct ERMExecEnvironment if(funcVars) { if(retIt) - ret = funcVars->locals + initV-1; + { + ret.val.integervar = &funcVars->getLocal(initV); + ret.type = IexpValStr::INTVAR; + } else - initV = funcVars->params[initV - 1]; + initV = funcVars->getLocal(initV); } else throw EIexpProblem("Function local variables cannot be used outside a function!"); @@ -772,9 +794,12 @@ struct ERMExecEnvironment if(trigEnv) { if(retIt) - ret = trigEnv->ermLocalVars.yvar - initV + 1; + { + ret.val.integervar = &trigEnv->ermLocalVars.getYvar(initV); + ret.type = IexpValStr::INTVAR; + } else - initV = trigEnv->ermLocalVars.yvar[-initV + 1]; + initV = trigEnv->ermLocalVars.getYvar(initV); } else throw EIexpProblem("Trigger local variables cannot be used outside triggers!"); @@ -792,15 +817,17 @@ struct ERMExecEnvironment if(retIt) { //these C-style casts are here just to shut up compiler errors - if(initV > 0 && initV <= ermGlobalEnv->NUM_STRINGS) + if(initV > 0 ) { - ret = (T*)ermGlobalEnv->strings + initV - 1; + ret.val.stringvar = &ermGlobalEnv->getZVar(initV); + ret.type = IexpValStr::STRINGVAR; } - else if(initV < 0 && initV >= -FunctionLocalVars::NUM_STRINGS) + else if(initV < 0) { if(funcVars) { - ret = (T*)funcVars->strings + initV - 1; + ret.val.stringvar = &funcVars->getString(initV); + ret.type = IexpValStr::STRINGVAR; } else throw EIexpProblem("Function local string variables cannot be used outside functions!"); @@ -829,76 +856,71 @@ namespace IexpDisemboweler enum EDir{GET, SET}; } -template -struct LVL2IexpDisemboweler : boost::static_visitor<> +struct LVL2IexpDisemboweler : boost::static_visitor { - T * inout; IexpDisemboweler::EDir dir; /*const*/ ERMExecEnvironment * env; - LVL2IexpDisemboweler(T * in_out, /*const*/ ERMExecEnvironment * _env, IexpDisemboweler::EDir _dir) - : inout(in_out), env(_env), dir(_dir) //writes value to given var + LVL2IexpDisemboweler(/*const*/ ERMExecEnvironment * _env, IexpDisemboweler::EDir _dir) + : env(_env), dir(_dir) //writes value to given var {} - void processNotMacro(const TVarExpNotMacro & val) const + IexpValStr processNotMacro(const TVarExpNotMacro & val) const { if(val.questionMark.is_initialized()) throw EIexpProblem("Question marks ('?') are not allowed in getter i-expressions"); //const-cast just to do some code-reuse... - *inout = *const_cast(env)->getVar(val.varsym, val.val); + return env->getVar(val.varsym, val.val); } - void operator()(TVarExpNotMacro const& val) const + IexpValStr operator()(TVarExpNotMacro const& val) const { - processNotMacro(val); + return processNotMacro(val); } - void operator()(TMacroUsage const& val) const + IexpValStr operator()(TMacroUsage const& val) const { std::map::const_iterator it = env->ermGlobalEnv->macroBindings.find(val .macro); if(it == env->ermGlobalEnv->macroBindings.end()) throw EUsageOfUndefinedMacro(val.macro); - else - processNotMacro(it->second); + + return processNotMacro(it->second); } }; -template -struct LVL1IexpDisemboweler : boost::static_visitor<> +struct LVL1IexpDisemboweler : boost::static_visitor { - T * inout; IexpDisemboweler::EDir dir; /*const*/ ERMExecEnvironment * env; - LVL1IexpDisemboweler(T * in_out, /*const*/ ERMExecEnvironment * _env, IexpDisemboweler::EDir _dir) - : inout(in_out), env(_env), dir(_dir) //writes value to given var + LVL1IexpDisemboweler(/*const*/ ERMExecEnvironment * _env, IexpDisemboweler::EDir _dir) + : env(_env), dir(_dir) //writes value to given var {} - void operator()(int const & constant) const + IexpValStr operator()(int const & constant) const { if(dir == IexpDisemboweler::GET) { - *inout = constant; + IexpValStr ret; + ret.val.val = constant; + ret.type = IexpValStr::INT; } else { throw EIexpProblem("Cannot set a constant!"); } } - void operator()(TVarExp const & var) const + IexpValStr operator()(TVarExp const & var) const { - boost::apply_visitor(LVL2IexpDisemboweler(inout, env, dir), var); + return boost::apply_visitor(LVL2IexpDisemboweler(env, dir), var); } }; -template -T ERMInterpreter::getIexp( const ERM::TIexp & iexp, /*const*/ Trigger * trig /*= NULL*/, /*const*/ FunctionLocalVars * fun /*= NULL*/) const +IexpValStr ERMInterpreter::getIexp( const ERM::TIexp & iexp, /*const*/ Trigger * trig /*= NULL*/, /*const*/ FunctionLocalVars * fun /*= NULL*/) const { - T ret; ERMExecEnvironment env(ermGlobalEnv, trig, fun); - boost::apply_visitor(LVL1IexpDisemboweler(&ret, &env, IexpDisemboweler::GET), iexp); - return ret; + return boost::apply_visitor(LVL1IexpDisemboweler(&env, IexpDisemboweler::GET), iexp); } void ERMInterpreter::executeTriggerType( VERMInterpreter::TriggerType tt, bool pre, const std::map< int, std::vector > & identifier ) @@ -936,6 +958,131 @@ ERM::Ttrigger ERMInterpreter::retrieveTrigger( ERM::TLine line ) throw ELineProblem("Given line is not an ERM trigger!"); } +template +bool compareExp(const T & lhs, const T & rhs, std::string op) +{ + if(op == "<") + { + return lhs < rhs; + } + else if(op == ">") + { + return lhs > rhs; + } + else if(op == ">=" || op == "=>") + { + return lhs >= rhs; + } + else if(op == "<=" || op == "=<") + { + return lhs <= rhs; + } + else if(op == "==") + { + return lhs == rhs; + } + else if(op == "<>" || op == "><") + { + return lhs != rhs; + } + else + throw EScriptExecError(std::string("Wrong comparison sign: ") + op); +} + +struct ConditionDisemboweler : boost::static_visitor +{ + ConditionDisemboweler(ERMInterpreter * _ei) : ei(_ei) + {} + + bool operator()(TComparison const & cmp) const + { + IexpValStr lhs = ei->getIexp(cmp.lhs), + rhs = ei->getIexp(cmp.rhs); + switch (lhs.type) + { + case IexpValStr::FLOATVAR: + switch (rhs.type) + { + case IexpValStr::FLOATVAR: + return compareExp(*lhs.val.flvar, *rhs.val.flvar, cmp.compSign); + break; + default: + throw EScriptExecError("Incompatible types for comparison"); + } + break; + case IexpValStr::INT: + switch (rhs.type) + { + case IexpValStr::INT: + return compareExp(lhs.val.val, rhs.val.val, cmp.compSign); + break; + case IexpValStr::INTVAR: + return compareExp(lhs.val.val, *rhs.val.integervar, cmp.compSign); + default: + throw EScriptExecError("Incompatible types for comparison"); + } + break; + case IexpValStr::INTVAR: + switch (rhs.type) + { + case IexpValStr::INT: + return compareExp(*lhs.val.integervar, rhs.val.val, cmp.compSign); + break; + case IexpValStr::INTVAR: + return compareExp(*lhs.val.integervar, *rhs.val.integervar, cmp.compSign); + default: + throw EScriptExecError("Incompatible types for comparison"); + } + break; + case IexpValStr::STRINGVAR: + switch (rhs.type) + { + case IexpValStr::STRINGVAR: + return compareExp(*lhs.val.stringvar, *rhs.val.stringvar, cmp.compSign); + break; + default: + throw EScriptExecError("Incompatible types for comparison"); + } + break; + default: + throw EScriptExecError("Wrong type of left iexp!"); + } + //we should never reach this place + } + bool operator()(int const & flag) const + { + return ei->ermGlobalEnv->getFlag(flag); + } +private: + ERMInterpreter * ei; +}; + +bool ERMInterpreter::checkCondition( ERM::Tcondition cond ) +{ + bool ret = boost::apply_visitor(ConditionDisemboweler(this), cond.cond); + if(cond.rhs.is_initialized()) + { //taking care of rhs expression + bool rhs = checkCondition(cond.rhs.get().get()); + switch (cond.ctype) + { + case '&': + ret &= rhs; + break; + case '|': + ret |= rhs; + break; + case 'X': + ret ^= rhs; + break; + default: + throw EInterpreterProblem(std::string("Strange - wrong condition connection (") + cond.ctype + ") !"); + break; + } + } + + return ret; +} + const std::string ERMInterpreter::triggerSymbol = "trigger"; const std::string ERMInterpreter::postTriggerSymbol = "postTrigger"; const std::string ERMInterpreter::defunSymbol = "defun"; @@ -953,7 +1100,16 @@ struct TriggerIdMatchHelper : boost::static_visitor<> void operator()(TIexp const& iexp) const { - ret = interpreter->getIexp(iexp, trig); + IexpValStr val = interpreter->getIexp(iexp, trig); + switch(val.type) + { + case IexpValStr::INT: + ret = val.val.val; + case IexpValStr::INTVAR: + ret = *val.val.integervar; + default: + throw EScriptExecError("Incompatible i-exp type!"); + } } void operator()(TArithmeticOp const& arop) const { @@ -963,6 +1119,8 @@ struct TriggerIdMatchHelper : boost::static_visitor<> bool TriggerIdentifierMatch::tryMatch( Trigger * interptrig ) const { + bool ret = true; + const ERM::Ttrigger & trig = ERMInterpreter::retrieveTrigger(ermEnv->retrieveLine(interptrig->line)); if(trig.identifier.is_initialized()) { @@ -970,7 +1128,7 @@ bool TriggerIdentifierMatch::tryMatch( Trigger * interptrig ) const ERM::Tidentifier tid = trig.identifier.get(); std::map< int, std::vector >::const_iterator it = matchToIt.find(tid.size()); if(it == matchToIt.end()) - return false; + ret = false; else { const std::vector & pattern = it->second; @@ -980,17 +1138,29 @@ bool TriggerIdentifierMatch::tryMatch( Trigger * interptrig ) const boost::apply_visitor(TriggerIdMatchHelper(val, ermEnv, interptrig), tid[g]); if(pattern[g] != val) { - return false; + ret = false; } } - return true; + ret = true; } } else { - if(allowNoIdetifier) + ret = allowNoIdetifier; + } + + //check condition + if(ret) + { + if(trig.condition.is_initialized()) + { + return ermEnv->checkCondition(trig.condition.get()); + } + else //no condition return true; } + else + return false; } VERMInterpreter::ERMEnvironment::ERMEnvironment() @@ -1004,6 +1174,36 @@ VERMInterpreter::ERMEnvironment::ERMEnvironment() flags[g] = false; } +int & VERMInterpreter::ERMEnvironment::getQuickVar( const char letter ) +{ + assert(letter >= 'f' && letter <= 't'); //it should be check by another function, just making sure here + return quickVars[letter - 'f']; +} + +int & VERMInterpreter::ERMEnvironment::getStandardVar( int num ) +{ + if(num < 1 || num > NUM_STANDARDS) + throw EScriptExecError("Number of standard variable out of bounds"); + + return standardVars[num-1]; +} + +std::string & VERMInterpreter::ERMEnvironment::getZVar( int num ) +{ + if(num < 1 || num > NUM_STRINGS) + throw EScriptExecError("Number of string variable out of bounds"); + + return strings[num-1]; +} + +bool & VERMInterpreter::ERMEnvironment::getFlag( int num ) +{ + if(num < 1 || num > NUM_FLAGS) + throw EScriptExecError("Number of flag out of bounds"); + + return flags[num-1]; +} + VERMInterpreter::TriggerLocalVars::TriggerLocalVars() { for(int g=0; g EVAR_NUM) + throw EScriptExecError("Number of trigger local floating point variable out of bounds"); + + return evar[num-1]; +} + +int & VERMInterpreter::TriggerLocalVars::getYvar( int num ) +{ + if(num < 1 || num > YVAR_NUM) + throw EScriptExecError("Number of trigger local variable out of bounds"); + + return yvar[num-1]; +} + bool VERMInterpreter::Environment::isBound( const std::string & name, bool globalOnly ) const { std::map::const_iterator it = symbols.find(name); @@ -1064,3 +1281,36 @@ bool VERMInterpreter::Environment::unbind( const std::string & name, EUnbindMode //neither bound nor have lexical parent return false; } + +int & VERMInterpreter::FunctionLocalVars::getParam( int num ) +{ + if(num < 1 || num > NUM_PARAMETERS) + throw EScriptExecError("Number of parameter out of bounds"); + + return params[num-1]; +} + +int & VERMInterpreter::FunctionLocalVars::getLocal( int num ) +{ + if(num < 1 || num > NUM_LOCALS) + throw EScriptExecError("Number of local variable out of bounds"); + + return locals[num-1]; +} + +std::string & VERMInterpreter::FunctionLocalVars::getString( int num ) +{ + num = -num; //we deal with negative indices + if(num < 1 || num > NUM_PARAMETERS) + throw EScriptExecError("Number of function local string variable out of bounds"); + + return strings[num-1]; +} + +double & VERMInterpreter::FunctionLocalVars::getFloat( int num ) +{ + if(num < 1 || num > NUM_FLOATINGS) + throw EScriptExecError("Number of float var out of bounds"); + + return floats[num-1]; +} diff --git a/lib/ERMInterpreter.h b/lib/ERMInterpreter.h index 5d5befb95..ffa1e9158 100644 --- a/lib/ERMInterpreter.h +++ b/lib/ERMInterpreter.h @@ -125,25 +125,33 @@ namespace VERMInterpreter struct TriggerLocalVars { static const int EVAR_NUM = 100; //number of evar locals - double evar[EVAR_NUM]; //negative indices static const int YVAR_NUM = 100; //number of yvar locals - int yvar[YVAR_NUM]; TriggerLocalVars(); + + double & getEvar(int num); + int & getYvar(int num); + private: + double evar[EVAR_NUM]; //negative indices + int yvar[YVAR_NUM]; + }; struct FunctionLocalVars { static const int NUM_PARAMETERS = 16; //number of function parameters - int params[NUM_PARAMETERS]; //x-vars - static const int NUM_LOCALS = 100; - int locals[NUM_LOCALS]; //y-vars - static const int NUM_STRINGS = 10; - std::string strings[NUM_STRINGS]; //z-vars (negative indices) - static const int NUM_FLOATINGS = 100; + + int & getParam(int num); + int & getLocal(int num); + std::string & getString(int num); + double & getFloat(int num); + private: + int params[NUM_PARAMETERS]; //x-vars + int locals[NUM_LOCALS]; //y-vars + std::string strings[NUM_STRINGS]; //z-vars (negative indices) double floats[NUM_FLOATINGS]; //e-vars (positive indices) }; @@ -151,22 +159,22 @@ namespace VERMInterpreter { ERMEnvironment(); static const int NUM_QUICKS = 't' - 'f' + 1; //it should be 15 - int quickVars[NUM_QUICKS]; //referenced by letter ('f' to 't' inclusive) - int & getQuickVar(const char letter) - { - assert(letter >= 'f' && letter <= 't'); //it should be check by another function, just makign sure here - return quickVars[letter - 'f']; - } + int & getQuickVar(const char letter); + int & getStandardVar(int num); + std::string & getZVar(int num); + bool & getFlag(int num); static const int NUM_STANDARDS = 1000; - int standardVars[NUM_STANDARDS]; //v-vars static const int NUM_STRINGS = 1000; - std::string strings[NUM_STRINGS]; //z-vars (positive indices) std::map macroBindings; static const int NUM_FLAGS = 1000; + private: + int quickVars[NUM_QUICKS]; //referenced by letter ('f' to 't' inclusive) + int standardVars[NUM_STANDARDS]; //v-vars + std::string strings[NUM_STRINGS]; //z-vars (positive indices) bool flags[NUM_FLAGS]; }; @@ -294,11 +302,24 @@ struct TriggerIdentifierMatch bool tryMatch(VERMInterpreter::Trigger * interptrig) const; }; +struct IexpValStr +{ + union + { + int val; + int * integervar; + double * flvar; + std::string * stringvar; + } val; + enum {WRONGVAL, INT, INTVAR, FLOATVAR, STRINGVAR} type; +}; + class ERMInterpreter { friend class ScriptScanner; friend class TriggerIdMatchHelper; friend class TriggerIdentifierMatch; + friend class ConditionDisemboweler; std::vector files; std::vector< VERMInterpreter::FileInfo* > fileInfos; @@ -314,7 +335,7 @@ class ERMInterpreter template void setIexp(const ERM::TIexp & iexp, const T & val, VERMInterpreter::Trigger * trig = NULL); - template T getIexp(const ERM::TIexp & iexp, /*const*/ VERMInterpreter::Trigger * trig = NULL, /*const*/ VERMInterpreter::FunctionLocalVars * fun = NULL) const; + IexpValStr getIexp(const ERM::TIexp & iexp, /*const*/ VERMInterpreter::Trigger * trig = NULL, /*const*/ VERMInterpreter::FunctionLocalVars * fun = NULL) const; static const std::string triggerSymbol, postTriggerSymbol, defunSymbol; @@ -333,4 +354,5 @@ public: void scanScripts(); //scans for functions, triggers etc. ERMInterpreter(); + bool checkCondition( ERM::Tcondition cond ); };