Forráskód Böngészése

* basic structure of ERM interpreter
* SHOW_FPS moved to settings.txt
* minor changes

mateuszb 14 éve
szülő
commit
7874d84c4e

+ 2 - 2
client/CAnimation.h

@@ -246,10 +246,10 @@ public:
 	~CAnimImage();//d-tor
 
 	//change displayed frame on this one
-	void setFrame(size_t Frame, size_t Group=0);
+	void setFrame(size_t Frame, size_t Group=0);
 
 	//makes image player-colored
-	void playerColored(int player);
+	void playerColored(int player);
 
 	void showAll(SDL_Surface *to);
 };

+ 1 - 0
client/CConfigHandler.cpp

@@ -212,6 +212,7 @@ struct SettingsGrammar : public grammar<SettingsGrammar>
 				| str_p("server=") >> ( ( +digit_p >> *('.' >> +digit_p) )[assign_a(conf.cc.server)]   | eps_p[lerror("Wrong server!")])
 				| str_p("defaultPlayerAI=") >> ((+(anychar_p - ';'))[assign_a(conf.cc.defaultPlayerAI)] | eps_p[lerror("Wrong defaultAI!")])
 				| str_p("neutralBattleAI=") >> ((+(anychar_p - ';'))[assign_a(conf.cc.defaultBattleAI)] | eps_p[lerror("Wrong defaultAI!")])
+				| str_p("showFPS=") >> (uint_p[assign_a(conf.cc.showFPS)] | eps_p[lerror("Wrong showFPS!")])
 				| (+(anychar_p - '}'))[lerror2("Unrecognized client option: ")]
 				;
 			clientOptionsSequence = *(clientOption >> (';' | eps_p[lerror("Semicolon lacking after client option!")]));

+ 1 - 0
client/CConfigHandler.h

@@ -24,6 +24,7 @@ namespace config
 		int port, localInformation;
 		std::string server, //server address (e.g. 127.0.0.1)
 			defaultPlayerAI, defaultBattleAI; //dll names
+		bool showFPS; //show/hide FPS counter
 	};
 	
 	struct ButtonInfo

+ 2 - 1
client/GUIBase.cpp

@@ -9,6 +9,7 @@
 #include "CBitmapHandler.h"
 #include "Graphics.h"
 #include "../CThreadHelper.h"
+#include "CConfigHandler.h"
 
 /*
  * GUIBase.cpp, part of VCMI engine
@@ -375,7 +376,7 @@ void CGuiHandler::run()
 			if (this->invalidateSimpleRedraw == true)
 				internalSimpleRedraw();
 
-			if (SHOW_FPS)
+			if (conf.cc.showFPS)
 				drawFPSCounter();
 
 			mainFPSmng->framerateDelay(); // holds a constant FPS

+ 0 - 1
client/GUIBase.h

@@ -519,7 +519,6 @@ private:
 	void internalSimpleRedraw();
 
 public:
-	const static bool SHOW_FPS = false; // shows a fps counter when set to true
 	FPSManager *mainFPSmng; //to keep const framerate
 	timeHandler th;
 	std::list<IShowActivable *> listInt; //list of interfaces - front=foreground; back = background (includes adventure map, window interfaces, all kind of active dialogs, and so on)

+ 1 - 0
config/settings.txt

@@ -12,6 +12,7 @@ clientSettings
 	localInformation=2; //0 - *all* information sent from server (safest and slowest); 1 - map information sent from server; 2 - all information local-storaged
 	defaultPlayerAI=GeniusAI; 
 	neutralBattleAI=StupidAI;
+	showFPS=0;
 }
 GUISettings
 {

+ 388 - 0
lib/ERMInterpreter.cpp

@@ -0,0 +1,388 @@
+#include "ERMInterpreter.h"
+
+#include <boost/filesystem.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/foreach.hpp>
+
+/*
+ * ERMInterpreter.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+namespace spirit = boost::spirit;
+
+namespace ERMPrinter
+{
+	//console printer
+	using namespace ERM;
+
+	struct VarPrinterVisitor : boost::static_visitor<>
+	{
+		void operator()(TVarExpNotMacro const& val) const
+		{
+			tlog2 << val.varsym;
+			if(val.val.is_initialized())
+			{
+				tlog2 << val.val.get();
+			}
+		}
+		void operator()(TMacroUsage const& val) const
+		{
+			tlog2 << "$" << val.macro << "&";
+		}
+	};
+
+	void varPrinter(const TVarExp & var)
+	{
+		boost::apply_visitor(VarPrinterVisitor(), var);
+	}
+
+	struct IExpPrinterVisitor : boost::static_visitor<>
+	{
+		void operator()(int const & constant) const
+		{
+			tlog2 << constant;
+		}
+		void operator()(TVarExp const & var) const
+		{
+			varPrinter(var);
+		}
+	};
+
+
+	void iexpPrinter(const TIexp & exp)
+	{
+		boost::apply_visitor(IExpPrinterVisitor(), exp);
+	}
+
+	struct IdentifierPrinterVisitor : boost::static_visitor<>
+	{
+		void operator()(TIexp const& iexp) const
+		{
+			iexpPrinter(iexp);
+		}
+		void operator()(TArithmeticOp const& arop) const
+		{
+			iexpPrinter(arop.lhs);
+			tlog2 << " " << arop.opcode << " ";
+			iexpPrinter(arop.rhs);
+		}
+	};
+
+	void identifierPrinter(const boost::optional<Tidentifier> & id)
+	{
+		if(id.is_initialized())
+		{
+			tlog2 << "identifier: ";
+			BOOST_FOREACH(TIdentifierInternal x, id.get())
+			{
+				tlog2 << "#";
+				boost::apply_visitor(IdentifierPrinterVisitor(), x);
+			}
+		}
+	}
+
+	struct ConditionCondPrinterVisitor : boost::static_visitor<>
+	{
+		void operator()(TComparison const& cmp) const
+		{
+			iexpPrinter(cmp.lhs);
+			tlog2 << " " << cmp.compSign << " ";
+			iexpPrinter(cmp.rhs);
+		}
+		void operator()(int const& flag) const
+		{
+			tlog2 << "condflag " << flag;
+		}
+	};
+
+	void conditionPrinter(const boost::optional<Tcondition> & cond)
+	{
+		if(cond.is_initialized())
+		{
+			Tcondition condp = cond.get();
+			tlog2 << " condition: ";
+			boost::apply_visitor(ConditionCondPrinterVisitor(), condp.cond);
+			tlog2 << " cond type: " << condp.ctype;
+
+			//recursive call
+			if(condp.rhs.is_initialized())
+			{
+				tlog2 << "rhs: ";
+				boost::optional<Tcondition> rhsc = condp.rhs.get().get();
+				conditionPrinter(rhsc);
+			}
+			else
+			{
+				tlog2 << "no rhs; ";
+			}
+		}
+	}
+
+	struct BodyVarpPrinterVisitor : boost::static_visitor<>
+	{
+		void operator()(TVarExpNotMacro const& cmp) const
+		{
+			if(cmp.questionMark.is_initialized())
+			{
+				tlog2 << cmp.questionMark.get();
+			}
+			if(cmp.val.is_initialized())
+			{
+				tlog2 << "val:" << cmp.val.get();
+			}
+			tlog2 << "varsym: |" << cmp.varsym << "|";
+		}
+		void operator()(TQMacroUsage const& cmp) const
+		{
+			tlog2 << "???$$" << cmp.qmacro << "$$";
+		}
+	};
+
+	struct BodyOptionItemPrinterVisitor : boost::static_visitor<>
+	{
+		void operator()(TVarConcatString const& cmp) const
+		{
+			tlog2 << "+concat\"";
+			varPrinter(cmp.var);
+			tlog2 << " with " << cmp.string.str;
+		}
+		void operator()(TStringConstant const& cmp) const
+		{
+			tlog2 << " \"" << cmp.str << "\" ";
+		}
+		void operator()(TCurriedString const& cmp) const
+		{
+			tlog2 << "cs: ";
+			iexpPrinter(cmp.iexp);
+			tlog2 << " '" << cmp.string.str << "' ";
+		}
+		void operator()(TSemiCompare const& cmp) const
+		{
+			tlog2 << cmp.compSign << "; rhs: ";
+			iexpPrinter(cmp.rhs);
+		}
+		void operator()(TMacroUsage const& cmp) const
+		{
+			tlog2 << "$$" << cmp.macro << "$$";
+		}
+		void operator()(TMacroDef const& cmp) const
+		{
+			tlog2 << "@@" << cmp.macro << "@@";
+		}
+		void operator()(TIexp const& cmp) const
+		{
+			iexpPrinter(cmp);
+		}
+		void operator()(TVarpExp const& cmp) const
+		{
+			tlog2 << "varp";
+			boost::apply_visitor(BodyVarpPrinterVisitor(), cmp.var);
+		}
+		void operator()(spirit::unused_type const& cmp) const
+		{
+			tlog2 << "nothing";
+		}
+	};
+
+	struct BodyOptionVisitor : boost::static_visitor<>
+	{
+		void operator()(TVRLogic const& cmp) const
+		{
+			tlog2 << cmp.opcode << " ";
+			iexpPrinter(cmp.var);
+		}
+		void operator()(TVRArithmetic const& cmp) const
+		{
+			tlog2 << cmp.opcode << " ";
+			iexpPrinter(cmp.rhs);
+		}
+		void operator()(TNormalBodyOption const& cmp) const
+		{
+			tlog2 << cmp.optionCode << "~";
+			BOOST_FOREACH(TBodyOptionItem optList, cmp.params)
+			{
+				boost::apply_visitor(BodyOptionItemPrinterVisitor(), optList);
+			}
+		}
+	};
+
+	void bodyPrinter(const Tbody & body)
+	{
+		tlog2 << " body items: ";
+		BOOST_FOREACH(TBodyOption bi, body)
+		{
+			tlog2 << " (";
+			apply_visitor(BodyOptionVisitor(), bi);
+			tlog2 << ") ";
+		}
+	}
+
+	struct CommandPrinterVisitor : boost::static_visitor<>
+	{
+		void operator()(Ttrigger const& trig) const
+		{
+			tlog2 << "trigger: " << trig.name << " ";
+			identifierPrinter(trig.identifier);
+			conditionPrinter(trig.condition);
+		}
+		void operator()(Tinstruction const& trig) const
+		{
+			tlog2 << "instruction: " << trig.name << " ";
+			identifierPrinter(trig.identifier);
+			conditionPrinter(trig.condition);
+			bodyPrinter(trig.body);
+
+		}
+		void operator()(Treceiver const& trig) const
+		{
+			tlog2 << "receiver: " << trig.name << " ";
+
+			identifierPrinter(trig.identifier);
+			conditionPrinter(trig.condition);
+			if(trig.body.is_initialized())
+				bodyPrinter(trig.body.get());
+		}
+		void operator()(TPostTrigger const& trig) const
+		{
+			tlog2 << "post trigger: " << trig.name << " ";
+			identifierPrinter(trig.identifier);
+			conditionPrinter(trig.condition);
+		}
+	};
+
+	struct LinePrinterVisitor : boost::static_visitor<>
+	{
+		void operator()(Tcommand const& cmd) const
+		{
+			CommandPrinterVisitor un;
+			boost::apply_visitor(un, cmd.cmd);
+			std::cout << "Line comment: " << cmd.comment << std::endl;
+		}
+		void operator()(std::string const& comment) const
+		{
+		}
+		void operator()(spirit::unused_type const& nothing) const
+		{
+		}
+	};
+
+	void printERM(const TERMline & ast)
+	{
+		tlog2 << "";
+
+		boost::apply_visitor(LinePrinterVisitor(), ast);
+	}
+
+	void printTVExp(const TVExp & exp);
+
+	struct VOptionPrinterVisitor : boost::static_visitor<>
+	{
+		void operator()(TVExp const& cmd) const
+		{
+			printTVExp(cmd);
+		}
+		void operator()(TSymbol const& cmd) const
+		{
+			BOOST_FOREACH(TVModifier mod, cmd.symModifier)
+			{
+				tlog2 << mod << " ";
+			}
+			tlog2 << cmd.sym;
+		}
+		void operator()(char const& cmd) const
+		{
+			tlog2 << "'" << cmd << "'";
+		}
+		void operator()(int const& cmd) const
+		{
+			tlog2 << cmd;
+		}
+		void operator()(double const& cmd) const
+		{
+			tlog2 << cmd;
+		}
+		void operator()(TERMline const& cmd) const
+		{
+			printERM(cmd);
+		}
+		void operator()(TStringConstant const& cmd) const
+		{
+			tlog2 << "^" << cmd.str << "^";
+		}
+	};
+
+	void printTVExp(const TVExp & exp)
+	{
+		BOOST_FOREACH(TVModifier mod, exp.modifier)
+		{
+			tlog2 << mod << " ";
+		}
+		tlog2 << "[ ";
+		BOOST_FOREACH(TVOption opt, exp.children)
+		{
+			boost::apply_visitor(VOptionPrinterVisitor(), opt);
+			tlog2 << " ";
+		}
+		tlog2 << "]";
+	}
+
+	struct TLPrinterVisitor : boost::static_visitor<>
+	{
+		void operator()(TVExp const& cmd) const
+		{
+			printTVExp(cmd);
+		}
+		void operator()(TERMline const& cmd) const
+		{
+			printERM(cmd);
+		}
+	};
+
+	void printAST(const TLine & ast)
+	{
+		boost::apply_visitor(TLPrinterVisitor(), ast);
+		tlog2 << std::endl;
+	}
+}
+
+void ERMInterpreter::scanForScripts()
+{
+	using namespace boost::filesystem;
+	//parser checking
+	if(!exists(DATA_DIR "/Data/s/"))
+	{
+		tlog3 << "Warning: Folder " DATA_DIR "/Data/s/ doesn't exist!\n";
+		return;
+	}
+	directory_iterator enddir;
+	for (directory_iterator dir(DATA_DIR "/Data/s"); dir!=enddir; dir++)
+	{
+		if(is_regular(dir->status()))
+		{
+			std::string name = dir->path().leaf();
+			if( boost::algorithm::ends_with(name, ".erm") ||
+				boost::algorithm::ends_with(name, ".verm") )
+			{
+				ERMParser ep(dir->path().string());
+				scripts[name] = ep.parseFile();
+			}
+		}
+	}
+}
+
+void ERMInterpreter::printScripts( EPrintMode mode /*= EPrintMode::ALL*/ )
+{
+	for(std::map<std::string, std::vector<ERM::TLine> >::const_iterator it = scripts.begin(); it != scripts.end(); ++it)
+	{
+		tlog2 << "----------------- script " << it->first << " ------------------\n";
+		for(int i=0; i<it->second.size(); ++i)
+		{
+			ERMPrinter::printAST(it->second[i]);
+		}
+	}
+}

+ 23 - 0
lib/ERMInterpreter.h

@@ -0,0 +1,23 @@
+#pragma once
+#include "../global.h"
+#include "ERMParser.h"
+
+/*
+ * ERMInterpreter.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+class ERMInterpreter
+{
+	std::map<std::string, std::vector<ERM::TLine> > scripts;
+public:
+	void scanForScripts();
+	enum EPrintMode{ALL, ERM_ONLY, VERM_ONLY};
+	void printScripts(EPrintMode mode = ALL);
+	void startExecution();
+};

+ 54 - 561
lib/ERMParser.cpp

@@ -21,6 +21,16 @@ namespace qi = boost::spirit::qi;
 namespace ascii = spirit::ascii;
 namespace phoenix = boost::phoenix;
 
+/*
+ * ERMParser.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
 
 //Greenspun's Tenth Rule of Programming:
 //Any sufficiently complicated C or Fortran program contains an ad hoc, informally-specified,
@@ -58,6 +68,11 @@ CERMPreprocessor::CERMPreprocessor(const std::string &Fname) : fname(Fname), fil
 	}
 }
 
+class ParseErrorException : public std::exception
+{
+
+};
+
 std::string CERMPreprocessor::retreiveCommandLine()
 {
 	std::string wholeCommand;
@@ -136,6 +151,9 @@ std::string CERMPreprocessor::retreiveCommandLine()
 			line.erase(i, line.length() - i);
 		}
 
+		if(wholeCommand.size()) //separate lines with a space
+			wholeCommand += " ";
+
 		wholeCommand += line;
 		if(!openedBraces && !openedString)
 			return wholeCommand;
@@ -159,553 +177,27 @@ ERMParser::ERMParser(std::string file)
 	:srcFile(file)
 {}
 
-void ERMParser::parseFile()
+std::vector<ERM::TLine> ERMParser::parseFile()
 {
 	CERMPreprocessor preproc(srcFile);
-	while(1)
-	{
-		std::string command = preproc.retreiveCommandLine();
-		if(command.length() == 0)
-			break;
-
-		repairEncoding(command);
-		parseLine(command);
-	}
-}
-
-void callme(char const& i)
-{
-	std::cout << "fd";
-}
-
-namespace ERM
-{
-	struct TStringConstant
+	std::vector<ERM::TLine> ret;
+	try
 	{
-		std::string str;
-	};
-	struct TMacroUsage
-	{
-		std::string macro;
-	};
-
-	//macro with '?', for write only
-	struct TQMacroUsage
-	{
-		std::string qmacro;
-	};
-
-	//definition of a macro
-	struct TMacroDef
-	{
-		std::string macro;
-	};
-	typedef std::string TCmdName;
-	
-	struct TVarExpNotMacro
-	{
-		typedef boost::optional<int> Tval;
-		boost::optional<char> questionMark;
-		std::string varsym;
-		Tval val;
-	};
-
-	typedef boost::variant<TVarExpNotMacro, TMacroUsage> TVarExp;
-
-	//write-only variable expression
-	struct TVarpExp
-	{
-		typedef boost::variant<TVarExpNotMacro, TQMacroUsage> Tvartype;
-		Tvartype var;
-	};
-
-	//i-expression (identifier expression) - an integral constant, variable symbol or array symbol
-	typedef boost::variant<TVarExp, int> TIexp;
-
-	struct TArithmeticOp
-	{
-		TIexp lhs, rhs;
-		char opcode;
-	};
-
-	struct TVRLogic
-	{
-		char opcode;
-		TIexp var;
-	};
-
-	struct TVRArithmetic
-	{
-		char opcode;
-		TIexp rhs;
-	};
-
-	struct TSemiCompare
-	{
-		std::string compSign;
-		TIexp rhs;
-	};
-
-	struct TCurriedString
-	{
-		TIexp iexp;
-		TStringConstant string;
-	};
-
-	struct TVarConcatString 
-	{
-		TVarExp var;
-		TStringConstant string;
-	};
-
-	typedef boost::variant<TVarConcatString, TStringConstant, TCurriedString, TSemiCompare, TMacroUsage, TMacroDef, TIexp, TVarpExp, qi::unused_type> TBodyOptionItem;
-
-	typedef std::vector<TBodyOptionItem> TNormalBodyOptionList;
-
-	struct TNormalBodyOption
-	{
-		char optionCode;
-		TNormalBodyOptionList params;
-	};
-	typedef boost::variant<TVRLogic, TVRArithmetic, TNormalBodyOption> TBodyOption;
-
-	typedef boost::variant<TIexp, TArithmeticOp > TIdentifierInternal;
-	typedef std::vector< TIdentifierInternal > Tidentifier;
-
-	struct TComparison
-	{
-		std::string compSign;
-		TIexp lhs, rhs;
-	};
-
-	struct Tcondition;
-	typedef
-		boost::optional<
-		boost::recursive_wrapper<Tcondition>
-		>
-		TconditionNode;
-
-
-	struct Tcondition
-	{
-		typedef boost::variant<
-			TComparison,
-			int>
-			Tcond; //comparison or condition flag
-		char ctype;
-		Tcond cond;
-		TconditionNode rhs;
-	};
-
-	struct Ttrigger
-	{
-		TCmdName name;
-		boost::optional<Tidentifier> identifier;
-		boost::optional<Tcondition> condition;
-	};
-
-	//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
-	//
-	//moreover, I encountered a quite serious bug in boost: http://boost.2283326.n4.nabble.com/container-hpp-111-error-C2039-value-type-is-not-a-member-of-td3352328.html
-	//not sure how serious it is...
-
-	//typedef boost::variant<char, TStringConstant, TMacroUsage, TMacroDef> bodyItem;
- 	typedef std::vector<TBodyOption> Tbody;
-
-	struct Tinstruction
-	{
-		TCmdName name;
-		boost::optional<Tidentifier> identifier;
-		boost::optional<Tcondition> condition;
-		Tbody body;
-	};
-
-	struct Treceiver
-	{
-		TCmdName name;
-		boost::optional<Tidentifier> identifier;
-		boost::optional<Tcondition> condition;
-		boost::optional<Tbody> body;
-	};
-
-	struct TPostTrigger
-	{
-		TCmdName name;
-		boost::optional<Tidentifier> identifier;
-		boost::optional<Tcondition> condition;
-	};
-
-	struct Tcommand
-	{
-		typedef	boost::variant<
-			Ttrigger,
-			Tinstruction,
-			Treceiver,
-			TPostTrigger
-		>
-		Tcmd;
-		Tcmd cmd;
-		std::string comment;
-	};
-
-	//vector expression
-
-
-	typedef boost::variant<Tcommand, std::string, qi::unused_type> TERMline;
-
-	typedef std::string TVModifier; //'`', ',', ',@', '#''
-
-	struct TSymbol
-	{
-		std::vector<TVModifier> symModifier;
-		std::string sym;
-	};
-
-	//for #'symbol expression
-
-	struct TVExp;
-	typedef boost::variant<boost::recursive_wrapper<TVExp>, TSymbol, char, double, int, Tcommand, TStringConstant > TVOption; //options in v-expression
-	//v-expression
-	struct TVExp
-	{
-		std::vector<TVModifier> modifier;
-		std::vector<TVOption> children;
-	};
-
-	//script line
-	typedef boost::variant<TVExp, TERMline> TLine;
-
-	//console printer
-
-	struct VarPrinterVisitor : boost::static_visitor<>
-	{
-		void operator()(TVarExpNotMacro const& val) const
+		while(1)
 		{
-			tlog2 << val.varsym;
-			if(val.val.is_initialized())
-			{
-				tlog2 << val.val.get();
-			}
-		}
-		void operator()(TMacroUsage const& val) const
-		{
-			tlog2 << "$" << val.macro << "&";
-		}
-	};
-
-	void varPrinter(const TVarExp & var)
-	{
-		boost::apply_visitor(VarPrinterVisitor(), var);
-	}
+			std::string command = preproc.retreiveCommandLine();
+			if(command.length() == 0)
+				break;
 
-	struct IExpPrinterVisitor : boost::static_visitor<>
-	{
-		void operator()(int const & constant) const
-		{
-			tlog2 << constant;
-		}
-		void operator()(TVarExp const & var) const
-		{
-			varPrinter(var);
+			repairEncoding(command);
+			ret.push_back(parseLine(command));
 		}
-	};
-
-
-	void iexpPrinter(const TIexp & exp)
-	{
-		boost::apply_visitor(IExpPrinterVisitor(), exp);
 	}
-
-	struct IdentifierPrinterVisitor : boost::static_visitor<>
-	{
-		void operator()(TIexp const& iexp) const
-		{
-			iexpPrinter(iexp);
-		}
-		void operator()(TArithmeticOp const& arop) const
-		{
-			iexpPrinter(arop.lhs);
-			tlog2 << " " << arop.opcode << " ";
-			iexpPrinter(arop.rhs);
-		}
-	};
-
-	void identifierPrinter(const boost::optional<Tidentifier> & id)
+	catch (ParseErrorException & e)
 	{
-		if(id.is_initialized())
-		{
-			tlog2 << "identifier: ";
-			BOOST_FOREACH(TIdentifierInternal x, id.get())
-			{
-				tlog2 << "#";
-				boost::apply_visitor(IdentifierPrinterVisitor(), x);
-			}
-		}
-	}
-
-	struct ConditionCondPrinterVisitor : boost::static_visitor<>
-	{
-		void operator()(TComparison const& cmp) const
-		{
-			iexpPrinter(cmp.lhs);
-			tlog2 << " " << cmp.compSign << " ";
-			iexpPrinter(cmp.rhs);
-		}
-		void operator()(int const& flag) const
-		{
-			tlog2 << "condflag " << flag;
-		}
-	};
-
-	void conditionPrinter(const boost::optional<Tcondition> & cond)
-	{
-		if(cond.is_initialized())
-		{
-			Tcondition condp = cond.get();
-			tlog2 << " condition: ";
-			boost::apply_visitor(ConditionCondPrinterVisitor(), condp.cond);
-			tlog2 << " cond type: " << condp.ctype;
-			
-			//recursive call
-			if(condp.rhs.is_initialized())
-			{
-				tlog2 << "rhs: ";
-				boost::optional<Tcondition> rhsc = condp.rhs.get().get();
-				conditionPrinter(rhsc);
-			}
-			else
-			{
-				tlog2 << "no rhs; ";
-			}
-		}
-	}
-
-	struct BodyVarpPrinterVisitor : boost::static_visitor<>
-	{
-		void operator()(TVarExpNotMacro const& cmp) const
-		{
-			if(cmp.questionMark.is_initialized())
-			{
-				tlog2 << cmp.questionMark.get();
-			}
-			if(cmp.val.is_initialized())
-			{
-				tlog2 << "val:" << cmp.val.get();
-			}
-			tlog2 << "varsym: |" << cmp.varsym << "|";
-		}
-		void operator()(TQMacroUsage const& cmp) const
-		{
-			tlog2 << "???$$" << cmp.qmacro << "$$";
-		}
-	};
-
-	struct BodyOptionItemPrinterVisitor : boost::static_visitor<>
-	{
-		void operator()(TVarConcatString const& cmp) const
-		{
-			tlog2 << "+concat\"";
-			varPrinter(cmp.var);
-			tlog2 << " with " << cmp.string.str;
-		}
-		void operator()(TStringConstant const& cmp) const
-		{
-			tlog2 << " \"" << cmp.str << "\" ";
-		}
-		void operator()(TCurriedString const& cmp) const
-		{
-			tlog2 << "cs: ";
-			iexpPrinter(cmp.iexp);
-			tlog2 << " '" << cmp.string.str << "' ";
-		}
-		void operator()(TSemiCompare const& cmp) const
-		{
-			tlog2 << cmp.compSign << "; rhs: ";
-			iexpPrinter(cmp.rhs);
-		}
-		void operator()(TMacroUsage const& cmp) const
-		{
-			tlog2 << "$$" << cmp.macro << "$$";
-		}
-		void operator()(TMacroDef const& cmp) const
-		{
-			tlog2 << "@@" << cmp.macro << "@@";
-		}
-		void operator()(TIexp const& cmp) const
-		{
-			iexpPrinter(cmp);
-		}
-		void operator()(TVarpExp const& cmp) const
-		{
-			tlog2 << "varp";
-			boost::apply_visitor(BodyVarpPrinterVisitor(), cmp.var);
-		}
-		void operator()(qi::unused_type const& cmp) const
-		{
-			tlog2 << "nothing";
-		}
-	};
-
-	struct BodyOptionVisitor : boost::static_visitor<>
-	{
-		void operator()(TVRLogic const& cmp) const
-		{
-			tlog2 << cmp.opcode << " ";
-			iexpPrinter(cmp.var);
-		}
-		void operator()(TVRArithmetic const& cmp) const
-		{
-			tlog2 << cmp.opcode << " ";
-			iexpPrinter(cmp.rhs);
-		}
-		void operator()(TNormalBodyOption const& cmp) const
-		{
-			tlog2 << cmp.optionCode << "~";
-			BOOST_FOREACH(TBodyOptionItem optList, cmp.params)
-			{
-				boost::apply_visitor(BodyOptionItemPrinterVisitor(), optList);
-			}
-		}
-	};
-
-	void bodyPrinter(const Tbody & body)
-	{
-		tlog2 << " body items: ";
-		BOOST_FOREACH(TBodyOption bi, body)
-		{
-			tlog2 << " (";
-			apply_visitor(BodyOptionVisitor(), bi);
-			tlog2 << ") ";
-		}
-	}
-
-	struct CommandPrinterVisitor : boost::static_visitor<>
-	{
-		void operator()(Ttrigger const& trig) const
-		{
-			tlog2 << "trigger: " << trig.name << " ";
-			identifierPrinter(trig.identifier);
-			conditionPrinter(trig.condition);
-		}
-		void operator()(Tinstruction const& trig) const
-		{
-			tlog2 << "instruction: " << trig.name << " ";
-			identifierPrinter(trig.identifier);
-			conditionPrinter(trig.condition);
-			bodyPrinter(trig.body);
-			
-		}
-		void operator()(Treceiver const& trig) const
-		{
-			tlog2 << "receiver: " << trig.name << " ";
-
-			identifierPrinter(trig.identifier);
-			conditionPrinter(trig.condition);
-			if(trig.body.is_initialized())
-				bodyPrinter(trig.body.get());
-		}
-		void operator()(TPostTrigger const& trig) const
-		{
-			tlog2 << "post trigger: " << trig.name << " ";
-			identifierPrinter(trig.identifier);
-			conditionPrinter(trig.condition);
-		}
-	};
-
-	struct LinePrinterVisitor : boost::static_visitor<>
-	{
-		void operator()(Tcommand const& cmd) const
-		{
-			CommandPrinterVisitor un;
-			boost::apply_visitor(un, cmd.cmd);
-			std::cout << "Line comment: " << cmd.comment << std::endl;
-		}
-		void operator()(std::string const& comment) const
-		{
-		}
-		void operator()(qi::unused_type const& nothing) const
-		{
-		}
-	};
-
-	void printERM(const TERMline & ast)
-	{
-		tlog2 << "";
-		
-		boost::apply_visitor(LinePrinterVisitor(), ast);
-	}
-
-	void printTVExp(const TVExp & exp);
-
-	struct VOptionPrinterVisitor : boost::static_visitor<>
-	{
-		void operator()(TVExp const& cmd) const
-		{
-			printTVExp(cmd);
-		}
-		void operator()(TSymbol const& cmd) const
-		{
-			BOOST_FOREACH(TVModifier mod, cmd.symModifier)
-			{
-				tlog2 << mod << " ";
-			}
-			tlog2 << cmd.sym;
-		}
-		void operator()(char const& cmd) const
-		{
-			tlog2 << "'" << cmd << "'";
-		}
-		void operator()(int const& cmd) const
-		{
-			tlog2 << cmd;
-		}
-		void operator()(double const& cmd) const
-		{
-			tlog2 << cmd;
-		}
-		void operator()(TERMline const& cmd) const
-		{
-			printERM(cmd);
-		}
-		void operator()(TStringConstant const& cmd) const
-		{
-			tlog2 << "^" << cmd.str << "^";
-		}
-	};
-
-	void printTVExp(const TVExp & exp)
-	{
-		BOOST_FOREACH(TVModifier mod, exp.modifier)
-		{
-			tlog2 << mod << " ";
-		}
-		tlog2 << "[ ";
-		BOOST_FOREACH(TVOption opt, exp.children)
-		{
-			boost::apply_visitor(VOptionPrinterVisitor(), opt);
-			tlog2 << " ";
-		}
-		tlog2 << "]";
-	}
-
-	struct TLPrinterVisitor : boost::static_visitor<>
-	{
-		void operator()(TVExp const& cmd) const
-		{
-			printTVExp(cmd);
-		}
-		void operator()(TERMline const& cmd) const
-		{
-			printERM(cmd);
-		}
-	};
-
-	void printAST(const TLine & ast)
-	{
-		boost::apply_visitor(TLPrinterVisitor(), ast);
-		tlog2 << std::endl;
+		tlog1 << "stopped parsing file" << std::endl;
 	}
+	return ret;
 }
 
 BOOST_FUSION_ADAPT_STRUCT(
@@ -853,13 +345,13 @@ namespace ERM
 		ERM_grammar() : ERM_grammar::base_type(vline, "VERM script line")
 		{
 			//do not build too complicated expressions, e.g. (a >> b) | c, qi has problems with them
-			macroUsage %= qi::lexeme[qi::lit('$') >> *(qi::char_ - '$') >> qi::lit('$')];
-			macroDef %= qi::lexeme[qi::lit('@') >> *(qi::char_ - '@') >> qi::lit('@')];
+			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_;
-			qMacroUsage %= qi::lexeme[qi::lit("?$") >> *(qi::char_ - '$') >> qi::lit('$')];
-			varExp %= varExpNotMacro | macroUsage;
+			qERMMacroUsage %= qi::lexeme[qi::lit("?$") >> *(qi::char_ - '$') >> qi::lit('$')];
+			varExp %= varExpNotMacro | ERMmacroUsage;
 			iexp %= varExp | qi::int_;
-			varp %=/* qi::lit("?") >> */(varExpNotMacro | qMacroUsage);
+			varp %=/* qi::lit("?") >> */(varExpNotMacro | qERMMacroUsage);
  			comment %= *qi::char_;
 			commentLine %= (~qi::char_("!") >> comment | (qi::char_('!') >> (~qi::char_("?!$#[")) >> comment ));
  			cmdName %= qi::lexeme[qi::repeat(2)[qi::char_]];
@@ -877,7 +369,7 @@ namespace ERM
 			semiCompare %= *qi::char_("<=>") >> iexp;
 			curStr %= iexp >> string;
 			varConcatString %= varExp >> qi::lit("+") >> string;
-			bodyOptionItem %= varConcatString | curStr | string | semiCompare | macroUsage | macroDef | varp | iexp | qi::eps;
+			bodyOptionItem %= varConcatString | curStr | string | semiCompare | ERMmacroUsage | ERMmacroDef | varp | iexp | qi::eps;
 			exactBodyOptionList %= (bodyOptionItem % qi::lit("/"));
 			normalBodyOption = qi::char_("A-Z+") > exactBodyOptionList;
 			bodyOption %= VRLogic | VRarithmetic | normalBodyOption;
@@ -901,7 +393,7 @@ namespace ERM
 					command | commentLine | spirit::eps
 				);
 
-			vmod %= qi::string("`") | qi::string(",!") | qi::string(",") | qi::string("#'");
+			vmod %= qi::string("`") | qi::string(",!") | qi::string(",") | qi::string("#'") | qi::string("'");
 			vsym %= *vmod >> qi::lexeme[+qi::char_("+*/$%&_=<>~a-zA-Z0-9-")];
 
 			qi::real_parser<double, qi::strict_real_policies<double> > strict_double;
@@ -913,6 +405,11 @@ namespace ERM
 			//error handling
 
 			string.name("string constant");
+			ERMmacroUsage.name("macro usage");
+			qERMMacroUsage.name("macro usage with ?");
+			ERMmacroDef.name("macro definition");
+			varExpNotMacro.name("variable expression (not macro)");
+			varExp.name("variable expression");
 			iexp.name("i-expression");
 			comment.name("comment");
 			commentLine.name("comment line");
@@ -947,9 +444,9 @@ namespace ERM
 
 		qi::rule<Iterator, TStringConstant(), ascii::space_type> string;
 
-		qi::rule<Iterator, TMacroUsage(), ascii::space_type> macroUsage;
-		qi::rule<Iterator, TQMacroUsage(), ascii::space_type> qMacroUsage;
-		qi::rule<Iterator, TMacroDef(), ascii::space_type> macroDef;
+		qi::rule<Iterator, TMacroUsage(), ascii::space_type> ERMmacroUsage;
+		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;
 		qi::rule<Iterator, TIexp(), ascii::space_type> iexp;
@@ -985,7 +482,7 @@ namespace ERM
 	};
 };
 
-void ERMParser::parseLine( const std::string & line )
+ERM::TLine ERMParser::parseLine( const std::string & line )
 {
 	std::string::const_iterator beg = line.begin(),
 		end = line.end();
@@ -993,18 +490,14 @@ void ERMParser::parseLine( const std::string & line )
 	ERM::ERM_grammar<std::string::const_iterator> ERMgrammar;
 	ERM::TLine AST;
 
-//  	bool r = qi::phrase_parse(beg, end, ERMgrammar, ascii::space, AST);
-//  	if(!r || beg != end)
-//  	{
-//  		tlog1 << "Parse error for line (" << parsedLine << ") : " << line << std::endl;
-//  		tlog1 << "\tCannot parse: " << std::string(beg, end) << std::endl;
-//  	}
-//  	else
-//  	{
-//  		//parsing succeeded
-//  		tlog2 << line << std::endl;
-//  		ERM::printAST(AST);
-//  	}
+	bool r = qi::phrase_parse(beg, end, ERMgrammar, ascii::space, AST);
+	if(!r || beg != end)
+	{
+		tlog1 << "Parse error in file " << srcFile << " (line " << parsedLine << ") :\n" << line << std::endl;
+		tlog1 << "\tCannot parse: " << std::string(beg, end) << std::endl;
+		throw ParseErrorException();
+	}
+	return AST;
 }
 
 ERMParser::ELineType ERMParser::classifyLine( const std::string & line, bool inString ) const

+ 216 - 2
lib/ERMParser.h

@@ -1,6 +1,20 @@
 #pragma once
 #include "../global.h"
 #include <fstream>
+#include <boost/variant.hpp>
+#include <boost/optional.hpp>
+#include <boost/spirit/home/support/unused.hpp>
+
+/*
+ * ERMParser.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
 
 class CERMPreprocessor
 {
@@ -16,6 +30,206 @@ public:
 	std::string retreiveCommandLine();
 };
 
+//various classes that represent ERM/VERM AST
+namespace ERM
+{
+	struct TStringConstant
+	{
+		std::string str;
+	};
+	struct TMacroUsage
+	{
+		std::string macro;
+	};
+
+	//macro with '?', for write only
+	struct TQMacroUsage
+	{
+		std::string qmacro;
+	};
+
+	//definition of a macro
+	struct TMacroDef
+	{
+		std::string macro;
+	};
+	typedef std::string TCmdName;
+
+	struct TVarExpNotMacro
+	{
+		typedef boost::optional<int> Tval;
+		boost::optional<char> questionMark;
+		std::string varsym;
+		Tval val;
+	};
+
+	typedef boost::variant<TVarExpNotMacro, TMacroUsage> TVarExp;
+
+	//write-only variable expression
+	struct TVarpExp
+	{
+		typedef boost::variant<TVarExpNotMacro, TQMacroUsage> Tvartype;
+		Tvartype var;
+	};
+
+	//i-expression (identifier expression) - an integral constant, variable symbol or array symbol
+	typedef boost::variant<TVarExp, int> TIexp;
+
+	struct TArithmeticOp
+	{
+		TIexp lhs, rhs;
+		char opcode;
+	};
+
+	struct TVRLogic
+	{
+		char opcode;
+		TIexp var;
+	};
+
+	struct TVRArithmetic
+	{
+		char opcode;
+		TIexp rhs;
+	};
+
+	struct TSemiCompare
+	{
+		std::string compSign;
+		TIexp rhs;
+	};
+
+	struct TCurriedString
+	{
+		TIexp iexp;
+		TStringConstant string;
+	};
+
+	struct TVarConcatString 
+	{
+		TVarExp var;
+		TStringConstant string;
+	};
+
+	typedef boost::variant<TVarConcatString, TStringConstant, TCurriedString, TSemiCompare, TMacroUsage, TMacroDef, TIexp, TVarpExp, boost::spirit::unused_type> TBodyOptionItem;
+
+	typedef std::vector<TBodyOptionItem> TNormalBodyOptionList;
+
+	struct TNormalBodyOption
+	{
+		char optionCode;
+		TNormalBodyOptionList params;
+	};
+	typedef boost::variant<TVRLogic, TVRArithmetic, TNormalBodyOption> TBodyOption;
+
+	typedef boost::variant<TIexp, TArithmeticOp > TIdentifierInternal;
+	typedef std::vector< TIdentifierInternal > Tidentifier;
+
+	struct TComparison
+	{
+		std::string compSign;
+		TIexp lhs, rhs;
+	};
+
+	struct Tcondition;
+	typedef
+		boost::optional<
+		boost::recursive_wrapper<Tcondition>
+		>
+		TconditionNode;
+
+
+	struct Tcondition
+	{
+		typedef boost::variant<
+			TComparison,
+			int>
+			Tcond; //comparison or condition flag
+		char ctype;
+		Tcond cond;
+		TconditionNode rhs;
+	};
+
+	struct Ttrigger
+	{
+		TCmdName name;
+		boost::optional<Tidentifier> identifier;
+		boost::optional<Tcondition> condition;
+	};
+
+	//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
+	//
+	//moreover, I encountered a quite serious bug in boost: http://boost.2283326.n4.nabble.com/container-hpp-111-error-C2039-value-type-is-not-a-member-of-td3352328.html
+	//not sure how serious it is...
+
+	//typedef boost::variant<char, TStringConstant, TMacroUsage, TMacroDef> bodyItem;
+	typedef std::vector<TBodyOption> Tbody;
+
+	struct Tinstruction
+	{
+		TCmdName name;
+		boost::optional<Tidentifier> identifier;
+		boost::optional<Tcondition> condition;
+		Tbody body;
+	};
+
+	struct Treceiver
+	{
+		TCmdName name;
+		boost::optional<Tidentifier> identifier;
+		boost::optional<Tcondition> condition;
+		boost::optional<Tbody> body;
+	};
+
+	struct TPostTrigger
+	{
+		TCmdName name;
+		boost::optional<Tidentifier> identifier;
+		boost::optional<Tcondition> condition;
+	};
+
+	struct Tcommand
+	{
+		typedef	boost::variant<
+			Ttrigger,
+			Tinstruction,
+			Treceiver,
+			TPostTrigger
+		>
+		Tcmd;
+		Tcmd cmd;
+		std::string comment;
+	};
+
+	//vector expression
+
+
+	typedef boost::variant<Tcommand, std::string, boost::spirit::unused_type> TERMline;
+
+	typedef std::string TVModifier; //'`', ',', ',@', '#''
+
+	struct TSymbol
+	{
+		std::vector<TVModifier> symModifier;
+		std::string sym;
+	};
+
+	//for #'symbol expression
+
+	struct TVExp;
+	typedef boost::variant<boost::recursive_wrapper<TVExp>, TSymbol, char, double, int, Tcommand, TStringConstant > TVOption; //options in v-expression
+	//v-expression
+	struct TVExp
+	{
+		std::vector<TVModifier> modifier;
+		std::vector<TVOption> children;
+	};
+
+	//script line
+	typedef boost::variant<TVExp, TERMline> TLine;
+}
+
 class ERMParser
 {
 private:
@@ -26,10 +240,10 @@ private:
 	enum ELineType{COMMAND_FULL, COMMENT, UNFINISHED, END_OF};
 	int countHatsBeforeSemicolon(const std::string & line) const;
 	ELineType classifyLine(const std::string & line, bool inString) const;
-	void parseLine(const std::string & line);
+	ERM::TLine parseLine(const std::string & line);
 
 
 public:
 	ERMParser(std::string file);
-	void parseFile();
+	std::vector<ERM::TLine> parseFile();
 };

+ 4 - 26
lib/VCMI_Lib.cpp

@@ -11,10 +11,7 @@
 #include "CBuildingHandler.h"
 #include "CSpellHandler.h"
 #include "CGeneralTextHandler.h"
-#include "ERMParser.h"
-
-#include <boost/filesystem.hpp> //for erm parser testing
-#include <boost/algorithm/string.hpp> //for erm parser testing
+#include "ERMInterpreter.h"
 
 /*
  * VCMI_Lib.cpp, part of VCMI engine
@@ -55,28 +52,9 @@ DLL_EXPORT void initDLL(CConsoleHandler *Console, std::ostream *Logfile)
 	} HANDLE_EXCEPTION;
 
 
-	using namespace boost::filesystem;
-	//parser checking
-	if(!exists(DATA_DIR "/Data/s/"))
-	{
-		tlog3 << "Warning: Folder " DATA_DIR "/Data/s/ doesn't exist!\n";
-		return;
-	}
-	directory_iterator enddir;
-	for (directory_iterator dir(DATA_DIR "/Data/s"); dir!=enddir; dir++)
-	{
-		if(is_regular(dir->status()))
-		{
-			std::string name = dir->path().leaf();
-			if( boost::algorithm::ends_with(name, ".erm") ||
-				boost::algorithm::ends_with(name, ".verm") )
-			{
-
-				ERMParser ep(dir->path().string());
-				ep.parseFile();
-			}
-		}
-	}
+// 	ERMInterpreter ei;
+// 	ei.scanForScripts();
+// 	ei.printScripts();
 }
 
 DLL_EXPORT void loadToIt(std::string &dest, const std::string &src, int &iter, int mode)