2
0
Эх сурвалжийг харах

Various fixes and improvements for ERM:
* comparisons need to have comparison operator -> they won't catch plain var usage
* removed qmacro -> that's just reading into normal macro
* there are 10000 standard vars
* there is one global (base) set of y-vars
* the iterator from !!DO loop is correctly passed into called function
* fixed getting variable value (also supporting array indexing)

* post- and pre-triggers share common base

Michał W. Urbańczyk 14 жил өмнө
parent
commit
249977af2f

+ 29 - 19
lib/ERMInterpreter.cpp

@@ -143,9 +143,9 @@ namespace ERMPrinter
 			}
 			tlog2 << "varsym: |" << cmp.varsym << "|";
 		}
-		void operator()(TQMacroUsage const& cmp) const
+		void operator()(TMacroUsage const& cmp) const
 		{
-			tlog2 << "???$$" << cmp.qmacro << "$$";
+			tlog2 << "???$$" << cmp.macro << "$$";
 		}
 	};
 
@@ -471,7 +471,7 @@ void ERMInterpreter::executeTrigger( VERMInterpreter::Trigger & trig, int funNum
 		curFunc = getFuncVars(funNum);
 		for(int g=1; g<=FunctionLocalVars::NUM_PARAMETERS; ++g)
 		{
-			curFunc->getParam(g) = g < funParams.size() ? funParams[g] : 0;
+			curFunc->getParam(g) = g-1 < funParams.size() ? funParams[g-1] : 0;
 		}
 	}
 
@@ -769,12 +769,14 @@ struct ERMExpDispatch : boost::static_visitor<>
 
 				for(int it = startVal; it < stopVal; it += increment)
 				{
-					owner->getFuncVars(funNum)->getParam(16) = it;
+					std::vector<int> params(FunctionLocalVars::NUM_PARAMETERS, 0);
+					params.back() = it;
+					//owner->getFuncVars(funNum)->getParam(16) = it;
 					ERMInterpreter::TIDPattern tip;
 					std::vector<int> v1;
 					v1 += funNum;
 					insert(tip) (v1.size(), v1);
-					owner->executeTriggerType(TriggerType("FU"), true, tip);
+					owner->executeTriggerType(TriggerType("FU"), true, tip, params);
 					it = owner->getFuncVars(funNum)->getParam(16);
 				}
 			}
@@ -831,6 +833,7 @@ struct LineExec : boost::static_visitor<>
 
 void ERMInterpreter::executeLine( const LinePointer & lp )
 {
+	tlog0 << "Executing line nr " << getRealLine(lp.lineNum) << " (internal " << lp.lineNum << ") from " << lp.file << std::endl;
 	boost::apply_visitor(LineExec(this), scripts[lp]);
 }
 
@@ -839,7 +842,7 @@ void ERMInterpreter::init()
 	ermGlobalEnv = new ERMEnvironment();
 	globalEnv = new Environment();
 	//TODO: reset?
-	for(int g=0; g<TRIG_FUNC_NUM; ++g)
+	for(int g = 0; g < ARRAY_COUNT(funcVars); ++g)
 		funcVars[g].reset();
 }
 
@@ -874,9 +877,9 @@ IexpValStr ERMInterpreter::getVar(std::string toFollow, boost::optional<int> ini
 	//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
+		bool retIt = b == endNum/*+1*/; //if we should return the value are currently at
 
-		char cr = toFollow[toFollow.size() - 1];
+		char cr = toFollow[b];
 		if(cr == 'c')//write number of current day
 		{
 			//TODO
@@ -968,15 +971,11 @@ IexpValStr ERMInterpreter::getVar(std::string toFollow, boost::optional<int> ini
 			{
 				if(initV > 0 && initV <= FunctionLocalVars::NUM_LOCALS)
 				{
-					if(curFunc)
-					{
-						if(retIt)
-							ret = IexpValStr(&curFunc->getLocal(initV));
-						else
-							initV = curFunc->getLocal(initV);
-					}
+					int &valPtr = curFunc ? curFunc->getLocal(initV) : const_cast<ERMInterpreter&>(*this).getFuncVars(0)->getLocal(initV); //retreive local var if in function or use global set otherwise
+					if(retIt)
+						ret = IexpValStr(&valPtr);
 					else
-						throw EIexpProblem("Function local variables cannot be used outside a function!");
+						initV = curFunc->getLocal(initV);
 				}
 				else if(initV < 0 && initV >= -TriggerLocalVars::YVAR_NUM)
 				{
@@ -1114,7 +1113,7 @@ IexpValStr ERMInterpreter::getIexp( const ERM::TIdentifierInternal & tid ) const
 		throw EScriptExecError("Identifier must be a valid i-expression to perform this operation!");
 }
 
-void ERMInterpreter::executeTriggerType( VERMInterpreter::TriggerType tt, bool pre, const TIDPattern & identifier )
+void ERMInterpreter::executeTriggerType( VERMInterpreter::TriggerType tt, bool pre, const TIDPattern & identifier, const std::vector<int> &funParams/*=std::vector<int>()*/ )
 {
 	struct HLP
 	{
@@ -1138,7 +1137,7 @@ void ERMInterpreter::executeTriggerType( VERMInterpreter::TriggerType tt, bool p
 		if(tim.tryMatch(&triggersToTry[g]))
 		{
 			curTrigger = &triggersToTry[g];
-			executeTrigger(triggersToTry[g], HLP::calcFunNum(tt, identifier));
+			executeTrigger(triggersToTry[g], HLP::calcFunNum(tt, identifier), funParams);
 		}
 	}
 }
@@ -1289,7 +1288,9 @@ bool ERMInterpreter::checkCondition( ERM::Tcondition cond )
 
 FunctionLocalVars * ERMInterpreter::getFuncVars( int funNum )
 {
-	return funcVars + funNum - 1;
+	if(funNum >= ARRAY_COUNT(funcVars) || funNum < 0)
+		throw EScriptExecError("Attempt of accessing variables of function with index out of boundaries!");
+	return funcVars + funNum;
 }
 
 void ERMInterpreter::executeInstructions()
@@ -1297,6 +1298,15 @@ void ERMInterpreter::executeInstructions()
 	//TODO implement me
 }
 
+int ERMInterpreter::getRealLine(int lineNum)
+{
+	for(std::map<VERMInterpreter::LinePointer, ERM::TLine>::const_iterator i = scripts.begin(); i != scripts.end(); i++)
+		if(i->first.lineNum == lineNum)
+			return i->first.realLineNum;
+
+	return -1;
+}
+
 const std::string ERMInterpreter::triggerSymbol = "trigger";
 const std::string ERMInterpreter::postTriggerSymbol = "postTrigger";
 const std::string ERMInterpreter::defunSymbol = "defun";

+ 5 - 4
lib/ERMInterpreter.h

@@ -165,7 +165,7 @@ namespace VERMInterpreter
 		std::string & getZVar(int num);
 		bool & getFlag(int num);
 
-		static const int NUM_STANDARDS = 1000;
+		static const int NUM_STANDARDS = 10000;
 
 		static const int NUM_STRINGS = 1000;
 
@@ -494,8 +494,8 @@ class ERMInterpreter
 	VERMInterpreter::Trigger * curTrigger;
 	VERMInterpreter::FunctionLocalVars * curFunc;
 	static const int TRIG_FUNC_NUM = 30000;
-	VERMInterpreter::FunctionLocalVars funcVars[TRIG_FUNC_NUM];
-	VERMInterpreter::FunctionLocalVars * getFuncVars(int funNum);
+	VERMInterpreter::FunctionLocalVars funcVars[TRIG_FUNC_NUM+1]; //+1 because we use [0] as a global set of y-vars
+	VERMInterpreter::FunctionLocalVars * getFuncVars(int funNum); //0 is a global func-like set
 
 	IexpValStr getIexp(const ERM::TIexp & iexp) const;
 	IexpValStr getIexp(const ERM::TMacroUsage & macro) const;
@@ -512,7 +512,7 @@ class ERMInterpreter
 public:
 	typedef std::map< int, std::vector<int> > TIDPattern;
 	void executeInstructions(); //called when starting a new game, before most of the map settings are done
-	void executeTriggerType(VERMInterpreter::TriggerType tt, bool pre, const TIDPattern & identifier); //use this to run triggers
+	void executeTriggerType(VERMInterpreter::TriggerType tt, bool pre, const TIDPattern & identifier, const std::vector<int> &funParams=std::vector<int>()); //use this to run triggers
 	void executeTriggerType(const char *trigger, int id); //convenience version of above, for pre-trigger when there is only one argument
 	void executeTriggerType(const char *trigger); //convenience version of above, for pre-trigger when there are no args
 	void init(); //sets up environment etc.
@@ -524,4 +524,5 @@ public:
 
 	ERMInterpreter();
 	bool checkCondition( ERM::Tcondition cond );
+	int getRealLine(int lineNum);
 };

+ 10 - 9
lib/ERMParser.cpp

@@ -213,10 +213,10 @@ BOOST_FUSION_ADAPT_STRUCT(
 	(std::string, macro)
 	)
 
-BOOST_FUSION_ADAPT_STRUCT(
-	ERM::TQMacroUsage,
-	(std::string, qmacro)
-	)
+// BOOST_FUSION_ADAPT_STRUCT(
+// 	ERM::TQMacroUsage,
+// 	(std::string, qmacro)
+// 	)
 
 BOOST_FUSION_ADAPT_STRUCT(
 	ERM::TMacroDef,
@@ -351,10 +351,11 @@ namespace ERM
 			ERMmacroUsage %= qi::lexeme[qi::lit('$') >> *(qi::char_ - '$') >> qi::lit('$')];
 			ERMmacroDef %= qi::lexeme[qi::lit('@') >> *(qi::char_ - '@') >> qi::lit('@')];
 			varExpNotMacro %= -qi::char_("?") >> (+(qi::char_("a-z") - 'u')) >> -qi::int_;
-			qERMMacroUsage %= qi::lexeme[qi::lit("?$") >> *(qi::char_ - '$') >> qi::lit('$')];
+			//TODO: mixed var/macro expressions like in !!HE-1&407:Id$cost$; [script 13]
+			/*qERMMacroUsage %= qi::lexeme[qi::lit("?$") >> *(qi::char_ - '$') >> qi::lit('$')];*/
 			varExp %= varExpNotMacro | ERMmacroUsage;
 			iexp %= varExp | qi::int_;
-			varp %=/* qi::lit("?") >> */(varExpNotMacro | qERMMacroUsage);
+			varp %= qi::lit("?") >> (varExpNotMacro | ERMmacroUsage);
  			comment %= *qi::char_;
 			commentLine %= (~qi::char_("!") >> comment | (qi::char_('!') >> (~qi::char_("?!$#[")) >> comment ));
  			cmdName %= qi::lexeme[qi::repeat(2)[qi::char_]];
@@ -369,7 +370,7 @@ namespace ERM
 			
 			VRLogic %= qi::char_("&|X") >> iexp;
 			VRarithmetic %= qi::char_("+*:/%-") >> iexp;
-			semiCompare %= *qi::char_("<=>") >> iexp;
+			semiCompare %= +qi::char_("<=>") >> iexp;
 			curStr %= iexp >> string;
 			varConcatString %= varExp >> qi::lit("+") >> string;
 			bodyOptionItem %= varConcatString | curStr | string | semiCompare | ERMmacroUsage | ERMmacroDef | varp | iexp | qi::eps;
@@ -409,7 +410,7 @@ namespace ERM
 
 			string.name("string constant");
 			ERMmacroUsage.name("macro usage");
-			qERMMacroUsage.name("macro usage with ?");
+			/*qERMMacroUsage.name("macro usage with ?");*/
 			ERMmacroDef.name("macro definition");
 			varExpNotMacro.name("variable expression (not macro)");
 			varExp.name("variable expression");
@@ -448,7 +449,7 @@ namespace ERM
 		qi::rule<Iterator, TStringConstant(), ascii::space_type> string;
 
 		qi::rule<Iterator, TMacroUsage(), ascii::space_type> ERMmacroUsage;
-		qi::rule<Iterator, TQMacroUsage(), ascii::space_type> qERMMacroUsage;
+		/*qi::rule<Iterator, TQMacroUsage(), ascii::space_type> qERMMacroUsage;*/
 		qi::rule<Iterator, TMacroDef(), ascii::space_type> ERMmacroDef;
 		qi::rule<Iterator, TVarExpNotMacro(), ascii::space_type> varExpNotMacro;
 		qi::rule<Iterator, TVarExp(), ascii::space_type> varExp;

+ 24 - 14
lib/ERMParser.h

@@ -46,11 +46,11 @@ namespace ERM
 		std::string macro;
 	};
 
-	//macro with '?', for write only
-	struct TQMacroUsage
-	{
-		std::string qmacro;
-	};
+// 	//macro with '?', for write only
+// 	struct TQMacroUsage
+// 	{
+// 		std::string qmacro;
+// 	};
 
 	//definition of a macro
 	struct TMacroDef
@@ -72,7 +72,7 @@ namespace ERM
 	//write-only variable expression
 	struct TVarpExp
 	{
-		typedef boost::variant<TVarExpNotMacro, TQMacroUsage> Tvartype;
+		typedef boost::variant<TVarExpNotMacro, TMacroUsage> Tvartype;
 		Tvartype var;
 	};
 
@@ -154,13 +154,30 @@ namespace ERM
 		TconditionNode rhs;
 	};
 
-	struct Ttrigger
+	struct TTriggerBase
 	{
+		bool pre; //if false it's !$ post-trigger, elsewise it's !# (pre)trigger
 		TCmdName name;
 		boost::optional<Tidentifier> identifier;
 		boost::optional<Tcondition> condition;
 	};
 
+	struct Ttrigger : TTriggerBase
+	{
+		Ttrigger() 
+		{
+			pre = false;
+		}
+	};
+
+	struct TPostTrigger : TTriggerBase
+	{
+		TPostTrigger()
+		{
+			pre = true;
+		}
+	};
+
 	//a dirty workaround for preprocessor magic that prevents the use types with comma in it in BOOST_FUSION_ADAPT_STRUCT
 	//see http://comments.gmane.org/gmane.comp.lib.boost.user/62501 for some info
 	//
@@ -186,13 +203,6 @@ namespace ERM
 		boost::optional<Tbody> body;
 	};
 
-	struct TPostTrigger
-	{
-		TCmdName name;
-		boost::optional<Tidentifier> identifier;
-		boost::optional<Tcondition> condition;
-	};
-
 	struct Tcommand
 	{
 		typedef	boost::variant<