ERMInterpreter.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. #include "ERMInterpreter.h"
  2. #include <boost/filesystem.hpp>
  3. #include <boost/algorithm/string.hpp>
  4. #include <boost/foreach.hpp>
  5. /*
  6. * ERMInterpreter.cpp, part of VCMI engine
  7. *
  8. * Authors: listed in file AUTHORS in main folder
  9. *
  10. * License: GNU General Public License v2.0 or later
  11. * Full text of license available in license.txt file, in main folder
  12. *
  13. */
  14. namespace spirit = boost::spirit;
  15. namespace VERMInterpreter
  16. {
  17. using namespace ERM;
  18. //different exceptions that can be thrown during interpreting
  19. class EInterpreterProblem : public std::exception
  20. {};
  21. class ESymbolNotFound : public EInterpreterProblem
  22. {
  23. std::string problem;
  24. public:
  25. ESymbolNotFound(const std::string & sym) : problem(std::string("Symbol ") + sym + std::string(" not found!"))
  26. {}
  27. const char * what() const throw() OVERRIDE
  28. {
  29. return problem.c_str();
  30. }
  31. };
  32. ///main environment class, manages symbols
  33. class Environment
  34. {
  35. private:
  36. std::map<std::string, TVOption> symbols;
  37. Environment * lexicalParent;
  38. public:
  39. bool isBound(const std::string & name, bool globalOnly) const
  40. {
  41. std::map<std::string, TVOption>::const_iterator it = symbols.find(name);
  42. if(globalOnly && lexicalParent)
  43. {
  44. return lexicalParent->isBound(name, globalOnly);
  45. }
  46. //we have it; if globalOnly is true, lexical parent is false here so we are global env
  47. if(it != symbols.end())
  48. return true;
  49. //here, we don;t have it; but parent can have
  50. if(lexicalParent)
  51. return lexicalParent->isBound(name, globalOnly);
  52. return false;
  53. }
  54. TVOption retrieveValue(const std::string & name) const
  55. {
  56. std::map<std::string, TVOption>::const_iterator it = symbols.find(name);
  57. if(it == symbols.end())
  58. {
  59. if(lexicalParent)
  60. {
  61. return lexicalParent->retrieveValue(name);
  62. }
  63. throw ESymbolNotFound(name);
  64. }
  65. return it->second;
  66. }
  67. ///returns true if symbols was really unbound
  68. enum EUnbindMode{LOCAL, RECURSIVE_UNTIL_HIT, FULLY_RECURSIVE};
  69. bool unbind(const std::string & name, EUnbindMode mode)
  70. {
  71. if(isBound(name, false))
  72. {
  73. if(symbols.find(name) != symbols.end()) //result of isBound could be from higher lexical env
  74. symbols.erase(symbols.find(name));
  75. if(mode == FULLY_RECURSIVE && lexicalParent)
  76. lexicalParent->unbind(name, mode);
  77. return true;
  78. }
  79. if(lexicalParent && (mode == RECURSIVE_UNTIL_HIT || mode == FULLY_RECURSIVE))
  80. return lexicalParent->unbind(name, mode);
  81. //neither bound nor have lexical parent
  82. return false;
  83. }
  84. };
  85. // All numeric variables are integer variables and have a range of -2147483647...+2147483647
  86. // c stores game active day number //indirect variable
  87. // d current value //not an actual variable but a modifier
  88. // e1..e100 Function floating point variables //local
  89. // e-1..e-100 Trigger local floating point variables //local
  90. // 'f'..'t' Standard variables ('quick variables') //global
  91. // v1..v1000 Standard variables //global
  92. // w1..w100 Hero variables
  93. // w101..w200 Hero variables
  94. // x1..x16 Function parameters //local
  95. // y1..y100 Function local variables //local
  96. // y-1..y-100 Trigger-based local integer variables //local
  97. // z1..z1000 String variables //global
  98. // z-1..z-10 Function local string variables //local
  99. struct TriggerLocalVars
  100. {
  101. static const int EVAR_NUM = 100; //number of evar locals
  102. double evar[EVAR_NUM]; //negative indices
  103. static const int YVAR_NUM = 100; //number of yvar locals
  104. int yvar[YVAR_NUM];
  105. };
  106. struct FunctionLocalVars
  107. {
  108. static const int NUM_PARAMETERS = 16; //number of function parameters
  109. int params[NUM_PARAMETERS]; //x-vars
  110. static const int NUM_LOCALS = 100;
  111. int locals[NUM_LOCALS]; //y-vars
  112. static const int NUM_STRINGS = 10;
  113. std::string strings[NUM_STRINGS]; //z-vars (negative indices)
  114. static const int NUM_FLOATINGS = 100;
  115. double floats[NUM_FLOATINGS]; //e-vars (positive indices)
  116. };
  117. struct ERMEnvironment
  118. {
  119. static const int NUM_QUICKS = 't' - 'f' + 1; //it should be 15
  120. int quickVars[NUM_QUICKS]; //referenced by letter ('f' to 't' inclusive)
  121. static const int NUM_STANDARDS = 1000;
  122. int standardVars[NUM_STANDARDS]; //v-vars
  123. static const int NUM_STRINGS = 1000;
  124. std::string strings[NUM_STRINGS]; //z-vars (positive indices)
  125. };
  126. //call stack
  127. class Stack
  128. {
  129. std::vector<int> entryPoints; //defines how to pass to current location
  130. Environment * env; //most nested VERM environment
  131. };
  132. }
  133. namespace ERMPrinter
  134. {
  135. //console printer
  136. using namespace ERM;
  137. struct VarPrinterVisitor : boost::static_visitor<>
  138. {
  139. void operator()(TVarExpNotMacro const& val) const
  140. {
  141. tlog2 << val.varsym;
  142. if(val.val.is_initialized())
  143. {
  144. tlog2 << val.val.get();
  145. }
  146. }
  147. void operator()(TMacroUsage const& val) const
  148. {
  149. tlog2 << "$" << val.macro << "&";
  150. }
  151. };
  152. void varPrinter(const TVarExp & var)
  153. {
  154. boost::apply_visitor(VarPrinterVisitor(), var);
  155. }
  156. struct IExpPrinterVisitor : boost::static_visitor<>
  157. {
  158. void operator()(int const & constant) const
  159. {
  160. tlog2 << constant;
  161. }
  162. void operator()(TVarExp const & var) const
  163. {
  164. varPrinter(var);
  165. }
  166. };
  167. void iexpPrinter(const TIexp & exp)
  168. {
  169. boost::apply_visitor(IExpPrinterVisitor(), exp);
  170. }
  171. struct IdentifierPrinterVisitor : boost::static_visitor<>
  172. {
  173. void operator()(TIexp const& iexp) const
  174. {
  175. iexpPrinter(iexp);
  176. }
  177. void operator()(TArithmeticOp const& arop) const
  178. {
  179. iexpPrinter(arop.lhs);
  180. tlog2 << " " << arop.opcode << " ";
  181. iexpPrinter(arop.rhs);
  182. }
  183. };
  184. void identifierPrinter(const boost::optional<Tidentifier> & id)
  185. {
  186. if(id.is_initialized())
  187. {
  188. tlog2 << "identifier: ";
  189. BOOST_FOREACH(TIdentifierInternal x, id.get())
  190. {
  191. tlog2 << "#";
  192. boost::apply_visitor(IdentifierPrinterVisitor(), x);
  193. }
  194. }
  195. }
  196. struct ConditionCondPrinterVisitor : boost::static_visitor<>
  197. {
  198. void operator()(TComparison const& cmp) const
  199. {
  200. iexpPrinter(cmp.lhs);
  201. tlog2 << " " << cmp.compSign << " ";
  202. iexpPrinter(cmp.rhs);
  203. }
  204. void operator()(int const& flag) const
  205. {
  206. tlog2 << "condflag " << flag;
  207. }
  208. };
  209. void conditionPrinter(const boost::optional<Tcondition> & cond)
  210. {
  211. if(cond.is_initialized())
  212. {
  213. Tcondition condp = cond.get();
  214. tlog2 << " condition: ";
  215. boost::apply_visitor(ConditionCondPrinterVisitor(), condp.cond);
  216. tlog2 << " cond type: " << condp.ctype;
  217. //recursive call
  218. if(condp.rhs.is_initialized())
  219. {
  220. tlog2 << "rhs: ";
  221. boost::optional<Tcondition> rhsc = condp.rhs.get().get();
  222. conditionPrinter(rhsc);
  223. }
  224. else
  225. {
  226. tlog2 << "no rhs; ";
  227. }
  228. }
  229. }
  230. struct BodyVarpPrinterVisitor : boost::static_visitor<>
  231. {
  232. void operator()(TVarExpNotMacro const& cmp) const
  233. {
  234. if(cmp.questionMark.is_initialized())
  235. {
  236. tlog2 << cmp.questionMark.get();
  237. }
  238. if(cmp.val.is_initialized())
  239. {
  240. tlog2 << "val:" << cmp.val.get();
  241. }
  242. tlog2 << "varsym: |" << cmp.varsym << "|";
  243. }
  244. void operator()(TQMacroUsage const& cmp) const
  245. {
  246. tlog2 << "???$$" << cmp.qmacro << "$$";
  247. }
  248. };
  249. struct BodyOptionItemPrinterVisitor : boost::static_visitor<>
  250. {
  251. void operator()(TVarConcatString const& cmp) const
  252. {
  253. tlog2 << "+concat\"";
  254. varPrinter(cmp.var);
  255. tlog2 << " with " << cmp.string.str;
  256. }
  257. void operator()(TStringConstant const& cmp) const
  258. {
  259. tlog2 << " \"" << cmp.str << "\" ";
  260. }
  261. void operator()(TCurriedString const& cmp) const
  262. {
  263. tlog2 << "cs: ";
  264. iexpPrinter(cmp.iexp);
  265. tlog2 << " '" << cmp.string.str << "' ";
  266. }
  267. void operator()(TSemiCompare const& cmp) const
  268. {
  269. tlog2 << cmp.compSign << "; rhs: ";
  270. iexpPrinter(cmp.rhs);
  271. }
  272. void operator()(TMacroUsage const& cmp) const
  273. {
  274. tlog2 << "$$" << cmp.macro << "$$";
  275. }
  276. void operator()(TMacroDef const& cmp) const
  277. {
  278. tlog2 << "@@" << cmp.macro << "@@";
  279. }
  280. void operator()(TIexp const& cmp) const
  281. {
  282. iexpPrinter(cmp);
  283. }
  284. void operator()(TVarpExp const& cmp) const
  285. {
  286. tlog2 << "varp";
  287. boost::apply_visitor(BodyVarpPrinterVisitor(), cmp.var);
  288. }
  289. void operator()(spirit::unused_type const& cmp) const
  290. {
  291. tlog2 << "nothing";
  292. }
  293. };
  294. struct BodyOptionVisitor : boost::static_visitor<>
  295. {
  296. void operator()(TVRLogic const& cmp) const
  297. {
  298. tlog2 << cmp.opcode << " ";
  299. iexpPrinter(cmp.var);
  300. }
  301. void operator()(TVRArithmetic const& cmp) const
  302. {
  303. tlog2 << cmp.opcode << " ";
  304. iexpPrinter(cmp.rhs);
  305. }
  306. void operator()(TNormalBodyOption const& cmp) const
  307. {
  308. tlog2 << cmp.optionCode << "~";
  309. BOOST_FOREACH(TBodyOptionItem optList, cmp.params)
  310. {
  311. boost::apply_visitor(BodyOptionItemPrinterVisitor(), optList);
  312. }
  313. }
  314. };
  315. void bodyPrinter(const Tbody & body)
  316. {
  317. tlog2 << " body items: ";
  318. BOOST_FOREACH(TBodyOption bi, body)
  319. {
  320. tlog2 << " (";
  321. apply_visitor(BodyOptionVisitor(), bi);
  322. tlog2 << ") ";
  323. }
  324. }
  325. struct CommandPrinterVisitor : boost::static_visitor<>
  326. {
  327. void operator()(Ttrigger const& trig) const
  328. {
  329. tlog2 << "trigger: " << trig.name << " ";
  330. identifierPrinter(trig.identifier);
  331. conditionPrinter(trig.condition);
  332. }
  333. void operator()(Tinstruction const& trig) const
  334. {
  335. tlog2 << "instruction: " << trig.name << " ";
  336. identifierPrinter(trig.identifier);
  337. conditionPrinter(trig.condition);
  338. bodyPrinter(trig.body);
  339. }
  340. void operator()(Treceiver const& trig) const
  341. {
  342. tlog2 << "receiver: " << trig.name << " ";
  343. identifierPrinter(trig.identifier);
  344. conditionPrinter(trig.condition);
  345. if(trig.body.is_initialized())
  346. bodyPrinter(trig.body.get());
  347. }
  348. void operator()(TPostTrigger const& trig) const
  349. {
  350. tlog2 << "post trigger: " << trig.name << " ";
  351. identifierPrinter(trig.identifier);
  352. conditionPrinter(trig.condition);
  353. }
  354. };
  355. struct LinePrinterVisitor : boost::static_visitor<>
  356. {
  357. void operator()(Tcommand const& cmd) const
  358. {
  359. CommandPrinterVisitor un;
  360. boost::apply_visitor(un, cmd.cmd);
  361. std::cout << "Line comment: " << cmd.comment << std::endl;
  362. }
  363. void operator()(std::string const& comment) const
  364. {
  365. }
  366. void operator()(spirit::unused_type const& nothing) const
  367. {
  368. }
  369. };
  370. void printERM(const TERMline & ast)
  371. {
  372. tlog2 << "";
  373. boost::apply_visitor(LinePrinterVisitor(), ast);
  374. }
  375. void printTVExp(const TVExp & exp);
  376. struct VOptionPrinterVisitor : boost::static_visitor<>
  377. {
  378. void operator()(TVExp const& cmd) const
  379. {
  380. printTVExp(cmd);
  381. }
  382. void operator()(TSymbol const& cmd) const
  383. {
  384. BOOST_FOREACH(TVModifier mod, cmd.symModifier)
  385. {
  386. tlog2 << mod << " ";
  387. }
  388. tlog2 << cmd.sym;
  389. }
  390. void operator()(char const& cmd) const
  391. {
  392. tlog2 << "'" << cmd << "'";
  393. }
  394. void operator()(int const& cmd) const
  395. {
  396. tlog2 << cmd;
  397. }
  398. void operator()(double const& cmd) const
  399. {
  400. tlog2 << cmd;
  401. }
  402. void operator()(TERMline const& cmd) const
  403. {
  404. printERM(cmd);
  405. }
  406. void operator()(TStringConstant const& cmd) const
  407. {
  408. tlog2 << "^" << cmd.str << "^";
  409. }
  410. };
  411. void printTVExp(const TVExp & exp)
  412. {
  413. BOOST_FOREACH(TVModifier mod, exp.modifier)
  414. {
  415. tlog2 << mod << " ";
  416. }
  417. tlog2 << "[ ";
  418. BOOST_FOREACH(TVOption opt, exp.children)
  419. {
  420. boost::apply_visitor(VOptionPrinterVisitor(), opt);
  421. tlog2 << " ";
  422. }
  423. tlog2 << "]";
  424. }
  425. struct TLPrinterVisitor : boost::static_visitor<>
  426. {
  427. void operator()(TVExp const& cmd) const
  428. {
  429. printTVExp(cmd);
  430. }
  431. void operator()(TERMline const& cmd) const
  432. {
  433. printERM(cmd);
  434. }
  435. };
  436. void printAST(const TLine & ast)
  437. {
  438. boost::apply_visitor(TLPrinterVisitor(), ast);
  439. tlog2 << std::endl;
  440. }
  441. }
  442. void ERMInterpreter::scanForScripts()
  443. {
  444. using namespace boost::filesystem;
  445. //parser checking
  446. if(!exists(DATA_DIR "/Data/s/"))
  447. {
  448. tlog3 << "Warning: Folder " DATA_DIR "/Data/s/ doesn't exist!\n";
  449. return;
  450. }
  451. directory_iterator enddir;
  452. for (directory_iterator dir(DATA_DIR "/Data/s"); dir!=enddir; dir++)
  453. {
  454. if(is_regular(dir->status()))
  455. {
  456. std::string name = dir->path().leaf();
  457. if( boost::algorithm::ends_with(name, ".erm") ||
  458. boost::algorithm::ends_with(name, ".verm") )
  459. {
  460. ERMParser ep(dir->path().string());
  461. scripts[name] = ep.parseFile();
  462. }
  463. }
  464. }
  465. }
  466. void ERMInterpreter::printScripts( EPrintMode mode /*= EPrintMode::ALL*/ )
  467. {
  468. for(std::map<std::string, std::vector<ERM::TLine> >::const_iterator it = scripts.begin(); it != scripts.end(); ++it)
  469. {
  470. tlog2 << "----------------- script " << it->first << " ------------------\n";
  471. for(int i=0; i<it->second.size(); ++i)
  472. {
  473. ERMPrinter::printAST(it->second[i]);
  474. }
  475. }
  476. }