ERMInterpreter.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  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. using namespace VERMInterpreter;
  16. namespace ERMPrinter
  17. {
  18. //console printer
  19. using namespace ERM;
  20. struct VarPrinterVisitor : boost::static_visitor<>
  21. {
  22. void operator()(TVarExpNotMacro const& val) const
  23. {
  24. tlog2 << val.varsym;
  25. if(val.val.is_initialized())
  26. {
  27. tlog2 << val.val.get();
  28. }
  29. }
  30. void operator()(TMacroUsage const& val) const
  31. {
  32. tlog2 << "$" << val.macro << "&";
  33. }
  34. };
  35. void varPrinter(const TVarExp & var)
  36. {
  37. boost::apply_visitor(VarPrinterVisitor(), var);
  38. }
  39. struct IExpPrinterVisitor : boost::static_visitor<>
  40. {
  41. void operator()(int const & constant) const
  42. {
  43. tlog2 << constant;
  44. }
  45. void operator()(TVarExp const & var) const
  46. {
  47. varPrinter(var);
  48. }
  49. };
  50. void iexpPrinter(const TIexp & exp)
  51. {
  52. boost::apply_visitor(IExpPrinterVisitor(), exp);
  53. }
  54. struct IdentifierPrinterVisitor : boost::static_visitor<>
  55. {
  56. void operator()(TIexp const& iexp) const
  57. {
  58. iexpPrinter(iexp);
  59. }
  60. void operator()(TArithmeticOp const& arop) const
  61. {
  62. iexpPrinter(arop.lhs);
  63. tlog2 << " " << arop.opcode << " ";
  64. iexpPrinter(arop.rhs);
  65. }
  66. };
  67. void identifierPrinter(const boost::optional<Tidentifier> & id)
  68. {
  69. if(id.is_initialized())
  70. {
  71. tlog2 << "identifier: ";
  72. BOOST_FOREACH(TIdentifierInternal x, id.get())
  73. {
  74. tlog2 << "#";
  75. boost::apply_visitor(IdentifierPrinterVisitor(), x);
  76. }
  77. }
  78. }
  79. struct ConditionCondPrinterVisitor : boost::static_visitor<>
  80. {
  81. void operator()(TComparison const& cmp) const
  82. {
  83. iexpPrinter(cmp.lhs);
  84. tlog2 << " " << cmp.compSign << " ";
  85. iexpPrinter(cmp.rhs);
  86. }
  87. void operator()(int const& flag) const
  88. {
  89. tlog2 << "condflag " << flag;
  90. }
  91. };
  92. void conditionPrinter(const boost::optional<Tcondition> & cond)
  93. {
  94. if(cond.is_initialized())
  95. {
  96. Tcondition condp = cond.get();
  97. tlog2 << " condition: ";
  98. boost::apply_visitor(ConditionCondPrinterVisitor(), condp.cond);
  99. tlog2 << " cond type: " << condp.ctype;
  100. //recursive call
  101. if(condp.rhs.is_initialized())
  102. {
  103. tlog2 << "rhs: ";
  104. boost::optional<Tcondition> rhsc = condp.rhs.get().get();
  105. conditionPrinter(rhsc);
  106. }
  107. else
  108. {
  109. tlog2 << "no rhs; ";
  110. }
  111. }
  112. }
  113. struct BodyVarpPrinterVisitor : boost::static_visitor<>
  114. {
  115. void operator()(TVarExpNotMacro const& cmp) const
  116. {
  117. if(cmp.questionMark.is_initialized())
  118. {
  119. tlog2 << cmp.questionMark.get();
  120. }
  121. if(cmp.val.is_initialized())
  122. {
  123. tlog2 << "val:" << cmp.val.get();
  124. }
  125. tlog2 << "varsym: |" << cmp.varsym << "|";
  126. }
  127. void operator()(TQMacroUsage const& cmp) const
  128. {
  129. tlog2 << "???$$" << cmp.qmacro << "$$";
  130. }
  131. };
  132. struct BodyOptionItemPrinterVisitor : boost::static_visitor<>
  133. {
  134. void operator()(TVarConcatString const& cmp) const
  135. {
  136. tlog2 << "+concat\"";
  137. varPrinter(cmp.var);
  138. tlog2 << " with " << cmp.string.str;
  139. }
  140. void operator()(TStringConstant const& cmp) const
  141. {
  142. tlog2 << " \"" << cmp.str << "\" ";
  143. }
  144. void operator()(TCurriedString const& cmp) const
  145. {
  146. tlog2 << "cs: ";
  147. iexpPrinter(cmp.iexp);
  148. tlog2 << " '" << cmp.string.str << "' ";
  149. }
  150. void operator()(TSemiCompare const& cmp) const
  151. {
  152. tlog2 << cmp.compSign << "; rhs: ";
  153. iexpPrinter(cmp.rhs);
  154. }
  155. void operator()(TMacroUsage const& cmp) const
  156. {
  157. tlog2 << "$$" << cmp.macro << "$$";
  158. }
  159. void operator()(TMacroDef const& cmp) const
  160. {
  161. tlog2 << "@@" << cmp.macro << "@@";
  162. }
  163. void operator()(TIexp const& cmp) const
  164. {
  165. iexpPrinter(cmp);
  166. }
  167. void operator()(TVarpExp const& cmp) const
  168. {
  169. tlog2 << "varp";
  170. boost::apply_visitor(BodyVarpPrinterVisitor(), cmp.var);
  171. }
  172. void operator()(spirit::unused_type const& cmp) const
  173. {
  174. tlog2 << "nothing";
  175. }
  176. };
  177. struct BodyOptionVisitor : boost::static_visitor<>
  178. {
  179. void operator()(TVRLogic const& cmp) const
  180. {
  181. tlog2 << cmp.opcode << " ";
  182. iexpPrinter(cmp.var);
  183. }
  184. void operator()(TVRArithmetic const& cmp) const
  185. {
  186. tlog2 << cmp.opcode << " ";
  187. iexpPrinter(cmp.rhs);
  188. }
  189. void operator()(TNormalBodyOption const& cmp) const
  190. {
  191. tlog2 << cmp.optionCode << "~";
  192. BOOST_FOREACH(TBodyOptionItem optList, cmp.params)
  193. {
  194. boost::apply_visitor(BodyOptionItemPrinterVisitor(), optList);
  195. }
  196. }
  197. };
  198. void bodyPrinter(const Tbody & body)
  199. {
  200. tlog2 << " body items: ";
  201. BOOST_FOREACH(TBodyOption bi, body)
  202. {
  203. tlog2 << " (";
  204. apply_visitor(BodyOptionVisitor(), bi);
  205. tlog2 << ") ";
  206. }
  207. }
  208. struct CommandPrinterVisitor : boost::static_visitor<>
  209. {
  210. void operator()(Ttrigger const& trig) const
  211. {
  212. tlog2 << "trigger: " << trig.name << " ";
  213. identifierPrinter(trig.identifier);
  214. conditionPrinter(trig.condition);
  215. }
  216. void operator()(Tinstruction const& trig) const
  217. {
  218. tlog2 << "instruction: " << trig.name << " ";
  219. identifierPrinter(trig.identifier);
  220. conditionPrinter(trig.condition);
  221. bodyPrinter(trig.body);
  222. }
  223. void operator()(Treceiver const& trig) const
  224. {
  225. tlog2 << "receiver: " << trig.name << " ";
  226. identifierPrinter(trig.identifier);
  227. conditionPrinter(trig.condition);
  228. if(trig.body.is_initialized())
  229. bodyPrinter(trig.body.get());
  230. }
  231. void operator()(TPostTrigger const& trig) const
  232. {
  233. tlog2 << "post trigger: " << trig.name << " ";
  234. identifierPrinter(trig.identifier);
  235. conditionPrinter(trig.condition);
  236. }
  237. };
  238. struct LinePrinterVisitor : boost::static_visitor<>
  239. {
  240. void operator()(Tcommand const& cmd) const
  241. {
  242. CommandPrinterVisitor un;
  243. boost::apply_visitor(un, cmd.cmd);
  244. std::cout << "Line comment: " << cmd.comment << std::endl;
  245. }
  246. void operator()(std::string const& comment) const
  247. {
  248. }
  249. void operator()(spirit::unused_type const& nothing) const
  250. {
  251. }
  252. };
  253. void printERM(const TERMline & ast)
  254. {
  255. tlog2 << "";
  256. boost::apply_visitor(LinePrinterVisitor(), ast);
  257. }
  258. void printTVExp(const TVExp & exp);
  259. struct VOptionPrinterVisitor : boost::static_visitor<>
  260. {
  261. void operator()(TVExp const& cmd) const
  262. {
  263. printTVExp(cmd);
  264. }
  265. void operator()(TSymbol const& cmd) const
  266. {
  267. BOOST_FOREACH(TVModifier mod, cmd.symModifier)
  268. {
  269. tlog2 << mod << " ";
  270. }
  271. tlog2 << cmd.sym;
  272. }
  273. void operator()(char const& cmd) const
  274. {
  275. tlog2 << "'" << cmd << "'";
  276. }
  277. void operator()(int const& cmd) const
  278. {
  279. tlog2 << cmd;
  280. }
  281. void operator()(double const& cmd) const
  282. {
  283. tlog2 << cmd;
  284. }
  285. void operator()(TERMline const& cmd) const
  286. {
  287. printERM(cmd);
  288. }
  289. void operator()(TStringConstant const& cmd) const
  290. {
  291. tlog2 << "^" << cmd.str << "^";
  292. }
  293. };
  294. void printTVExp(const TVExp & exp)
  295. {
  296. BOOST_FOREACH(TVModifier mod, exp.modifier)
  297. {
  298. tlog2 << mod << " ";
  299. }
  300. tlog2 << "[ ";
  301. BOOST_FOREACH(TVOption opt, exp.children)
  302. {
  303. boost::apply_visitor(VOptionPrinterVisitor(), opt);
  304. tlog2 << " ";
  305. }
  306. tlog2 << "]";
  307. }
  308. struct TLPrinterVisitor : boost::static_visitor<>
  309. {
  310. void operator()(TVExp const& cmd) const
  311. {
  312. printTVExp(cmd);
  313. }
  314. void operator()(TERMline const& cmd) const
  315. {
  316. printERM(cmd);
  317. }
  318. };
  319. void printAST(const TLine & ast)
  320. {
  321. boost::apply_visitor(TLPrinterVisitor(), ast);
  322. tlog2 << std::endl;
  323. }
  324. }
  325. void ERMInterpreter::scanForScripts()
  326. {
  327. using namespace boost::filesystem;
  328. //parser checking
  329. if(!exists(DATA_DIR "/Data/s/"))
  330. {
  331. tlog3 << "Warning: Folder " DATA_DIR "/Data/s/ doesn't exist!\n";
  332. return;
  333. }
  334. directory_iterator enddir;
  335. for (directory_iterator dir(DATA_DIR "/Data/s"); dir!=enddir; dir++)
  336. {
  337. if(is_regular(dir->status()))
  338. {
  339. std::string name = dir->path().leaf();
  340. if( boost::algorithm::ends_with(name, ".erm") ||
  341. boost::algorithm::ends_with(name, ".verm") )
  342. {
  343. ERMParser ep(dir->path().string());
  344. FileInfo * finfo = new FileInfo;
  345. finfo->filename = dir->path().string();
  346. std::vector<ERM::TLine> buf = ep.parseFile();
  347. finfo->length = buf.size();
  348. files.push_back(finfo);
  349. for(int g=0; g<buf.size(); ++g)
  350. {
  351. scripts[LinePointer(finfo, g)] = buf[g];
  352. }
  353. }
  354. }
  355. }
  356. }
  357. void ERMInterpreter::printScripts( EPrintMode mode /*= EPrintMode::ALL*/ )
  358. {
  359. std::map< LinePointer, ERM::TLine >::const_iterator prevIt;
  360. for(std::map< LinePointer, ERM::TLine >::const_iterator it = scripts.begin(); it != scripts.end(); ++it)
  361. {
  362. if(it == scripts.begin() || it->first.file != prevIt->first.file)
  363. {
  364. tlog2 << "----------------- script " << it->first.file->filename << " ------------------\n";
  365. }
  366. ERMPrinter::printAST(it->second);
  367. prevIt = it;
  368. }
  369. }
  370. void ERMInterpreter::scanScripts()
  371. {
  372. for(std::map< LinePointer, ERM::TLine >::const_iterator it = scripts.begin(); it != scripts.end(); ++it)
  373. {
  374. }
  375. }
  376. ERMInterpreter::ERMInterpreter()
  377. {
  378. globalEnv = new Environment();
  379. }
  380. void ERMInterpreter::executeTrigger( Trigger & trig )
  381. {
  382. for(LinePointer lp = trig.line; lp.isValid(); ++lp)
  383. {
  384. ERM::TLine curLine = retrieveLine(lp);
  385. if(isATrigger(curLine))
  386. break;
  387. executeLine(lp);
  388. }
  389. }
  390. bool ERMInterpreter::isATrigger( const ERM::TLine & line )
  391. {
  392. switch(line.which())
  393. {
  394. case 0: //v-exp
  395. {
  396. TVExp vexp = boost::get<TVExp>(line);
  397. if(vexp.children.size() == 0)
  398. return false;
  399. switch (getExpType(vexp.children[0]))
  400. {
  401. case SYMBOL:
  402. {
  403. //TODO: what about sym modifiers?
  404. //TOOD: macros
  405. ERM::TSymbol sym = boost::get<ERM::TSymbol>(vexp.children[0]);
  406. return sym.sym == triggerSymbol || sym.sym == postTriggerSymbol;
  407. }
  408. break;
  409. case TCMD:
  410. return isCMDATrigger( boost::get<ERM::Tcommand>(vexp.children[0]) );
  411. break;
  412. default:
  413. return false;
  414. break;
  415. }
  416. }
  417. break;
  418. case 1: //erm
  419. {
  420. TERMline line = boost::get<TERMline>(line);
  421. switch(line.which())
  422. {
  423. case 0: //tcmd
  424. return isCMDATrigger( boost::get<ERM::Tcommand>(line) );
  425. break;
  426. default:
  427. return false;
  428. break;
  429. }
  430. }
  431. break;
  432. default:
  433. assert(0); //it should never happen
  434. break;
  435. }
  436. assert(0);
  437. }
  438. ERM::EVOtions ERMInterpreter::getExpType( const ERM::TVOption & opt )
  439. {
  440. //MAINTENANCE: keep it correct!
  441. return static_cast<ERM::EVOtions>(opt.which());
  442. }
  443. bool ERMInterpreter::isCMDATrigger( const ERM::Tcommand & cmd )
  444. {
  445. switch (cmd.cmd.which())
  446. {
  447. case 0: //trigger
  448. case 3: //post trigger
  449. return true;
  450. break;
  451. default:
  452. return false;
  453. break;
  454. }
  455. }
  456. ERM::TLine ERMInterpreter::retrieveLine( LinePointer linePtr ) const
  457. {
  458. return *scripts.find(linePtr);
  459. }
  460. void ERMInterpreter::executeLine( const LinePointer & lp )
  461. {
  462. }
  463. const std::string ERMInterpreter::triggerSymbol = "trigger";
  464. const std::string ERMInterpreter::postTriggerSymbol = "postTrigger";