|
@@ -13,8 +13,156 @@
|
|
|
* Full text of license available in license.txt file, in main folder
|
|
|
*
|
|
|
*/
|
|
|
+
|
|
|
namespace spirit = boost::spirit;
|
|
|
|
|
|
+namespace VERMInterpreter
|
|
|
+{
|
|
|
+ using namespace ERM;
|
|
|
+
|
|
|
+ //different exceptions that can be thrown during interpreting
|
|
|
+ class EInterpreterProblem : public std::exception
|
|
|
+ {};
|
|
|
+
|
|
|
+ class ESymbolNotFound : public EInterpreterProblem
|
|
|
+ {
|
|
|
+ std::string problem;
|
|
|
+ public:
|
|
|
+ ESymbolNotFound(const std::string & sym) : problem(std::string("Symbol ") + sym + std::string(" not found!"))
|
|
|
+ {}
|
|
|
+
|
|
|
+ const char * what() const throw() OVERRIDE
|
|
|
+ {
|
|
|
+ return problem.c_str();
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
+ ///main environment class, manages symbols
|
|
|
+ class Environment
|
|
|
+ {
|
|
|
+ private:
|
|
|
+ std::map<std::string, TVOption> symbols;
|
|
|
+ Environment * lexicalParent;
|
|
|
+
|
|
|
+ public:
|
|
|
+ bool isBound(const std::string & name, bool globalOnly) const
|
|
|
+ {
|
|
|
+ std::map<std::string, TVOption>::const_iterator it = symbols.find(name);
|
|
|
+ if(globalOnly && lexicalParent)
|
|
|
+ {
|
|
|
+ return lexicalParent->isBound(name, globalOnly);
|
|
|
+ }
|
|
|
+
|
|
|
+ //we have it; if globalOnly is true, lexical parent is false here so we are global env
|
|
|
+ if(it != symbols.end())
|
|
|
+ return true;
|
|
|
+
|
|
|
+ //here, we don;t have it; but parent can have
|
|
|
+ if(lexicalParent)
|
|
|
+ return lexicalParent->isBound(name, globalOnly);
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ TVOption retrieveValue(const std::string & name) const
|
|
|
+ {
|
|
|
+ std::map<std::string, TVOption>::const_iterator it = symbols.find(name);
|
|
|
+ if(it == symbols.end())
|
|
|
+ {
|
|
|
+ if(lexicalParent)
|
|
|
+ {
|
|
|
+ return lexicalParent->retrieveValue(name);
|
|
|
+ }
|
|
|
+
|
|
|
+ throw ESymbolNotFound(name);
|
|
|
+ }
|
|
|
+ return it->second;
|
|
|
+ }
|
|
|
+
|
|
|
+ ///returns true if symbols was really unbound
|
|
|
+ enum EUnbindMode{LOCAL, RECURSIVE_UNTIL_HIT, FULLY_RECURSIVE};
|
|
|
+ bool unbind(const std::string & name, EUnbindMode mode)
|
|
|
+ {
|
|
|
+ if(isBound(name, false))
|
|
|
+ {
|
|
|
+ if(symbols.find(name) != symbols.end()) //result of isBound could be from higher lexical env
|
|
|
+ symbols.erase(symbols.find(name));
|
|
|
+
|
|
|
+ if(mode == FULLY_RECURSIVE && lexicalParent)
|
|
|
+ lexicalParent->unbind(name, mode);
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if(lexicalParent && (mode == RECURSIVE_UNTIL_HIT || mode == FULLY_RECURSIVE))
|
|
|
+ return lexicalParent->unbind(name, mode);
|
|
|
+
|
|
|
+ //neither bound nor have lexical parent
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+// All numeric variables are integer variables and have a range of -2147483647...+2147483647
|
|
|
+// c stores game active day number //indirect variable
|
|
|
+// d current value //not an actual variable but a modifier
|
|
|
+// e1..e100 Function floating point variables //local
|
|
|
+// e-1..e-100 Trigger local floating point variables //local
|
|
|
+// 'f'..'t' Standard variables ('quick variables') //global
|
|
|
+// v1..v1000 Standard variables //global
|
|
|
+// w1..w100 Hero variables
|
|
|
+// w101..w200 Hero variables
|
|
|
+// x1..x16 Function parameters //local
|
|
|
+// y1..y100 Function local variables //local
|
|
|
+// y-1..y-100 Trigger-based local integer variables //local
|
|
|
+// z1..z1000 String variables //global
|
|
|
+// z-1..z-10 Function local string variables //local
|
|
|
+
|
|
|
+ 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];
|
|
|
+ };
|
|
|
+
|
|
|
+ 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;
|
|
|
+ double floats[NUM_FLOATINGS]; //e-vars (positive indices)
|
|
|
+ };
|
|
|
+
|
|
|
+ struct ERMEnvironment
|
|
|
+ {
|
|
|
+ static const int NUM_QUICKS = 't' - 'f' + 1; //it should be 15
|
|
|
+ int quickVars[NUM_QUICKS]; //referenced by letter ('f' to 't' inclusive)
|
|
|
+
|
|
|
+ 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)
|
|
|
+ };
|
|
|
+
|
|
|
+ //call stack
|
|
|
+ class Stack
|
|
|
+ {
|
|
|
+ std::vector<int> entryPoints; //defines how to pass to current location
|
|
|
+ Environment * env; //most nested VERM environment
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
namespace ERMPrinter
|
|
|
{
|
|
|
//console printer
|