diff --git a/client/CAnimation.h b/client/CAnimation.h index 163d293f4..f4830889e 100644 --- a/client/CAnimation.h +++ b/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); }; diff --git a/client/CConfigHandler.cpp b/client/CConfigHandler.cpp index ded76f26d..a08e461cd 100644 --- a/client/CConfigHandler.cpp +++ b/client/CConfigHandler.cpp @@ -212,6 +212,7 @@ struct SettingsGrammar : public grammar | 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!")])); diff --git a/client/CConfigHandler.h b/client/CConfigHandler.h index 7809d5500..81e80f26d 100644 --- a/client/CConfigHandler.h +++ b/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 diff --git a/client/GUIBase.cpp b/client/GUIBase.cpp index a0ca7382d..378e472cd 100644 --- a/client/GUIBase.cpp +++ b/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 diff --git a/client/GUIBase.h b/client/GUIBase.h index 8b5bb74fc..31e2e5e13 100644 --- a/client/GUIBase.h +++ b/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 listInt; //list of interfaces - front=foreground; back = background (includes adventure map, window interfaces, all kind of active dialogs, and so on) diff --git a/config/settings.txt b/config/settings.txt index a721276d3..66a4a4258 100644 --- a/config/settings.txt +++ b/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 { diff --git a/lib/ERMInterpreter.cpp b/lib/ERMInterpreter.cpp new file mode 100644 index 000000000..ac31e364f --- /dev/null +++ b/lib/ERMInterpreter.cpp @@ -0,0 +1,388 @@ +#include "ERMInterpreter.h" + +#include +#include +#include + +/* + * 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 & 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 & 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 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 >::const_iterator it = scripts.begin(); it != scripts.end(); ++it) + { + tlog2 << "----------------- script " << it->first << " ------------------\n"; + for(int i=0; isecond.size(); ++i) + { + ERMPrinter::printAST(it->second[i]); + } + } +} diff --git a/lib/ERMInterpreter.h b/lib/ERMInterpreter.h new file mode 100644 index 000000000..105a18af8 --- /dev/null +++ b/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 > scripts; +public: + void scanForScripts(); + enum EPrintMode{ALL, ERM_ONLY, VERM_ONLY}; + void printScripts(EPrintMode mode = ALL); + void startExecution(); +}; \ No newline at end of file diff --git a/lib/ERMParser.cpp b/lib/ERMParser.cpp index 123a74646..bc7febee5 100644 --- a/lib/ERMParser.cpp +++ b/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 ERMParser::parseFile() { CERMPreprocessor preproc(srcFile); - while(1) + std::vector ret; + try { - 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::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 Tval; - boost::optional questionMark; - std::string varsym; - Tval val; - }; - - typedef boost::variant TVarExp; - - //write-only variable expression - struct TVarpExp - { - typedef boost::variant Tvartype; - Tvartype var; - }; - - //i-expression (identifier expression) - an integral constant, variable symbol or array symbol - typedef boost::variant 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 TBodyOptionItem; - - typedef std::vector TNormalBodyOptionList; - - struct TNormalBodyOption - { - char optionCode; - TNormalBodyOptionList params; - }; - typedef boost::variant TBodyOption; - - typedef boost::variant TIdentifierInternal; - typedef std::vector< TIdentifierInternal > Tidentifier; - - struct TComparison - { - std::string compSign; - TIexp lhs, rhs; - }; - - struct Tcondition; - typedef - boost::optional< - boost::recursive_wrapper - > - 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 identifier; - boost::optional 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 bodyItem; - typedef std::vector Tbody; - - struct Tinstruction - { - TCmdName name; - boost::optional identifier; - boost::optional condition; - Tbody body; - }; - - struct Treceiver - { - TCmdName name; - boost::optional identifier; - boost::optional condition; - boost::optional body; - }; - - struct TPostTrigger - { - TCmdName name; - boost::optional identifier; - boost::optional condition; - }; - - struct Tcommand - { - typedef boost::variant< - Ttrigger, - Tinstruction, - Treceiver, - TPostTrigger - > - Tcmd; - Tcmd cmd; - std::string comment; - }; - - //vector expression - - - typedef boost::variant TERMline; - - typedef std::string TVModifier; //'`', ',', ',@', '#'' - - struct TSymbol - { - std::vector symModifier; - std::string sym; - }; - - //for #'symbol expression - - struct TVExp; - typedef boost::variant, TSymbol, char, double, int, Tcommand, TStringConstant > TVOption; //options in v-expression - //v-expression - struct TVExp - { - std::vector modifier; - std::vector children; - }; - - //script line - typedef boost::variant 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 << "&"; - } - }; + std::string command = preproc.retreiveCommandLine(); + if(command.length() == 0) + break; - 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 & id) - { - if(id.is_initialized()) - { - tlog2 << "identifier: "; - BOOST_FOREACH(TIdentifierInternal x, id.get()) - { - tlog2 << "#"; - boost::apply_visitor(IdentifierPrinterVisitor(), x); - } + repairEncoding(command); + ret.push_back(parseLine(command)); } } - - struct ConditionCondPrinterVisitor : boost::static_visitor<> + catch (ParseErrorException & e) { - 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 & 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 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 > 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 string; - qi::rule macroUsage; - qi::rule qMacroUsage; - qi::rule macroDef; + qi::rule ERMmacroUsage; + qi::rule qERMMacroUsage; + qi::rule ERMmacroDef; qi::rule varExpNotMacro; qi::rule varExp; qi::rule 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 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 diff --git a/lib/ERMParser.h b/lib/ERMParser.h index 75df39314..76db6bee6 100644 --- a/lib/ERMParser.h +++ b/lib/ERMParser.h @@ -1,6 +1,20 @@ #pragma once #include "../global.h" #include +#include +#include +#include + +/* + * 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 Tval; + boost::optional questionMark; + std::string varsym; + Tval val; + }; + + typedef boost::variant TVarExp; + + //write-only variable expression + struct TVarpExp + { + typedef boost::variant Tvartype; + Tvartype var; + }; + + //i-expression (identifier expression) - an integral constant, variable symbol or array symbol + typedef boost::variant 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 TBodyOptionItem; + + typedef std::vector TNormalBodyOptionList; + + struct TNormalBodyOption + { + char optionCode; + TNormalBodyOptionList params; + }; + typedef boost::variant TBodyOption; + + typedef boost::variant TIdentifierInternal; + typedef std::vector< TIdentifierInternal > Tidentifier; + + struct TComparison + { + std::string compSign; + TIexp lhs, rhs; + }; + + struct Tcondition; + typedef + boost::optional< + boost::recursive_wrapper + > + 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 identifier; + boost::optional 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 bodyItem; + typedef std::vector Tbody; + + struct Tinstruction + { + TCmdName name; + boost::optional identifier; + boost::optional condition; + Tbody body; + }; + + struct Treceiver + { + TCmdName name; + boost::optional identifier; + boost::optional condition; + boost::optional body; + }; + + struct TPostTrigger + { + TCmdName name; + boost::optional identifier; + boost::optional condition; + }; + + struct Tcommand + { + typedef boost::variant< + Ttrigger, + Tinstruction, + Treceiver, + TPostTrigger + > + Tcmd; + Tcmd cmd; + std::string comment; + }; + + //vector expression + + + typedef boost::variant TERMline; + + typedef std::string TVModifier; //'`', ',', ',@', '#'' + + struct TSymbol + { + std::vector symModifier; + std::string sym; + }; + + //for #'symbol expression + + struct TVExp; + typedef boost::variant, TSymbol, char, double, int, Tcommand, TStringConstant > TVOption; //options in v-expression + //v-expression + struct TVExp + { + std::vector modifier; + std::vector children; + }; + + //script line + typedef boost::variant 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 parseFile(); }; diff --git a/lib/VCMI_Lib.cpp b/lib/VCMI_Lib.cpp index 60795de79..67acac04b 100644 --- a/lib/VCMI_Lib.cpp +++ b/lib/VCMI_Lib.cpp @@ -11,10 +11,7 @@ #include "CBuildingHandler.h" #include "CSpellHandler.h" #include "CGeneralTextHandler.h" -#include "ERMParser.h" - -#include //for erm parser testing -#include //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)