ff7_field_codegen.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. #include "ff7_field_codegen.h"
  2. #include "ff7_field_engine.h"
  3. #include <boost/algorithm/string/predicate.hpp>
  4. void FF7::FF7CodeGenerator::onBeforeStartFunction(const Function& func)
  5. {
  6. // Start class
  7. FunctionMetaData metaData(func._metadata);
  8. if (metaData.IsStart())
  9. {
  10. addOutputLine("EntityContainer[ \"" + metaData.EntityName() + "\" ] = {", false, true);
  11. if (metaData.CharacterId() != -1)
  12. {
  13. addOutputLine(metaData.EntityName() + " = nil,");
  14. }
  15. addOutputLine("");
  16. }
  17. }
  18. void FF7::FF7CodeGenerator::onStartFunction(const Function& func)
  19. {
  20. addOutputLine("--[[");
  21. for (const auto& inst : mInsts)
  22. {
  23. if (inst->_address >= func.mStartAddr && inst->_address <= func.mEndAddr)
  24. {
  25. std::stringstream output;
  26. output << inst;
  27. addOutputLine(output.str());
  28. }
  29. }
  30. addOutputLine("]]\n");
  31. }
  32. void FF7::FF7CodeGenerator::onEndFunction(const Function& func)
  33. {
  34. // End function
  35. addOutputLine("end,", true, false);
  36. // End class
  37. FunctionMetaData metaData(func._metadata);
  38. if (metaData.IsEnd())
  39. {
  40. addOutputLine("}", true, false);
  41. }
  42. }
  43. std::string FF7::FF7CodeGenerator::constructFuncSignature(const Function &func)
  44. {
  45. // Generate name
  46. return func._name + " = function( self )";
  47. }
  48. void FF7::FF7SimpleCodeGenerator::generate(InstVec& insts, const Graph& /*g*/)
  49. {
  50. // TODO: yes, this is a big monolithic whatever. it's also WIP and i will be breaking it into digestable chunks when it's ready :D
  51. auto instruction = insts.begin();
  52. std::vector<std::pair<Function&, InstVec>> functionsWithBodies;
  53. for (auto function = _engine->_functions.begin(); function != _engine->_functions.end(); ++function)
  54. {
  55. InstVec body;
  56. for (size_t i = 0; i < function->second.mNumInstructions; ++i, ++instruction)
  57. {
  58. body.push_back(*instruction);
  59. }
  60. functionsWithBodies.push_back(std::pair<Function&, InstVec> { function->second, body });
  61. }
  62. for (auto function = functionsWithBodies.begin(); function != functionsWithBodies.end(); ++function)
  63. {
  64. onBeforeStartFunction(function->first);
  65. auto signature = constructFuncSignature(function->first);
  66. addOutputLine(signature, false, true);
  67. onStartFunction(function->first);
  68. std::unordered_map<uint32, InstVec> labels;
  69. for (auto instruction = function->second.begin(); instruction != function->second.end(); ++instruction)
  70. {
  71. if ((*instruction)->isCondJump() || (*instruction)->isUncondJump())
  72. {
  73. auto targetAddr = (*instruction)->getDestAddress();
  74. auto label = labels.find(targetAddr);
  75. if (label == labels.end())
  76. {
  77. labels.insert({ targetAddr, InstVec() });
  78. }
  79. labels[targetAddr].push_back(*instruction);
  80. }
  81. }
  82. for (auto instruction = function->second.begin(); instruction != function->second.end(); ++instruction)
  83. {
  84. auto label = labels.find((*instruction)->_address);
  85. if (label != labels.end())
  86. {
  87. bool needLabel = false, needNewline = false;
  88. for (auto origin = label->second.begin(); origin != label->second.end(); ++origin)
  89. {
  90. if ((*origin)->isCondJump())
  91. {
  92. addOutputLine("end", true, false);
  93. needNewline = true;
  94. }
  95. else
  96. {
  97. needLabel = true;
  98. }
  99. }
  100. if (needNewline)
  101. {
  102. addOutputLine("");
  103. }
  104. if (needLabel)
  105. {
  106. addOutputLine((boost::format("::label_0x%1$X::") % label->first).str());
  107. }
  108. }
  109. ValueStack stack;
  110. (*instruction)->processInst(function->first, stack, _engine, this);
  111. if ((*instruction)->isCondJump())
  112. {
  113. addOutputLine((boost::format("if (%s) then") % stack.pop()->getString()).str(), false, true);
  114. // If there are no more instructions then ensure end is outputted
  115. if (instruction + 1 == std::end(function->second))
  116. {
  117. addOutputLine("end", true, false);
  118. }
  119. }
  120. else if ((*instruction)->isUncondJump())
  121. {
  122. addOutputLine((boost::format("goto label_0x%1$X") % (*instruction)->getDestAddress()).str());
  123. }
  124. // else, was already output'd
  125. }
  126. onEndFunction(function->first);
  127. }
  128. for (auto i = mLines.begin(); i != mLines.end(); ++i)
  129. {
  130. if (i->_unindentBefore)
  131. {
  132. assert(_indentLevel > 0);
  133. _indentLevel--;
  134. }
  135. _output << indentString(i->_line) << std::endl;
  136. if (i->_indentAfter)
  137. {
  138. _indentLevel++;
  139. }
  140. }
  141. }
  142. void FF7::FF7SimpleCodeGenerator::addOutputLine(std::string s, bool unindentBefore, bool indentAfter)
  143. {
  144. mLines.push_back(CodeLine(s, unindentBefore, indentAfter));
  145. }
  146. float FF7::FF7SimpleCodeGenerator::ScaleFactor() const
  147. {
  148. return static_cast<FF7::FF7FieldEngine*>(_engine)->ScaleFactor();
  149. }
  150. void FF7::FF7SimpleCodeGenerator::onBeforeStartFunction(const Function& func)
  151. {
  152. // Start class
  153. FunctionMetaData metaData(func._metadata);
  154. if (metaData.IsStart())
  155. {
  156. addOutputLine("EntityContainer[ \"" + metaData.EntityName() + "\" ] = {", false, true);
  157. if (metaData.CharacterId() != -1)
  158. {
  159. addOutputLine(metaData.EntityName() + " = nil,\n");
  160. }
  161. }
  162. const auto comment = mFormatter.FunctionComment(metaData.EntityName(), func._name);
  163. if (!comment.empty())
  164. {
  165. addOutputLine("-- " + comment);
  166. }
  167. }
  168. void FF7::FF7SimpleCodeGenerator::onStartFunction(const Function& func)
  169. {
  170. addOutputLine("--[[");
  171. for (const auto& inst : mInsts)
  172. {
  173. if (inst->_address >= func.mStartAddr && inst->_address <= func.mEndAddr)
  174. {
  175. std::stringstream output;
  176. output << inst;
  177. addOutputLine(output.str());
  178. }
  179. }
  180. addOutputLine("]]\n");
  181. if (func._name == "on_start" || func._name == "init")
  182. {
  183. addOutputLine("-- HACK ensure camera follows cloud, fix in engine properly later");
  184. addOutputLine("background2d:autoscroll_to_entity(entity_manager:get_entity(\"Cloud\"))");
  185. }
  186. }
  187. void FF7::FF7SimpleCodeGenerator::onEndFunction(const Function& func)
  188. {
  189. // End function
  190. addOutputLine("end,", true, false);
  191. // End class
  192. FunctionMetaData metaData(func._metadata);
  193. if (metaData.IsEnd())
  194. {
  195. addOutputLine("}\n\n\n", true, false);
  196. }
  197. else
  198. {
  199. addOutputLine("\n");
  200. }
  201. }
  202. std::string FF7::FF7SimpleCodeGenerator::constructFuncSignature(const Function &func)
  203. {
  204. // Generate name
  205. FunctionMetaData metaData(func._metadata);
  206. return mFormatter.FunctionName(metaData.EntityName(), func._name) + " = function( self )";
  207. }
  208. const std::string FF7::FF7CodeGeneratorHelpers::FormatInstructionNotImplemented(const std::string& entity, uint32 address, uint32 opcode)
  209. {
  210. return (boost::format("-- log:log(\"In entity \\\"%1%\\\", address 0x%2$08x: instruction 0x%3$04x not implemented\")") % entity % address % opcode).str();
  211. }
  212. const std::string FF7::FF7CodeGeneratorHelpers::FormatInstructionNotImplemented(const std::string& entity, uint32 address, const Instruction& instruction)
  213. {
  214. std::stringstream parameterList;
  215. for (auto i = instruction._params.begin(); i != instruction._params.end(); ++i)
  216. {
  217. if (i != instruction._params.begin())
  218. {
  219. parameterList << ", ";
  220. }
  221. parameterList << *i;
  222. }
  223. return (boost::format("-- log:log(\"In entity \\\"%1%\\\", address 0x%2$08x: instruction %3%( %4% ) not implemented\")") % entity % address % instruction._name % parameterList.str()).str();
  224. }
  225. const std::string FF7::FF7CodeGeneratorHelpers::FormatBool(uint32 value)
  226. {
  227. return value == 0 ? "false" : "true";
  228. }
  229. const std::string FF7::FF7CodeGeneratorHelpers::FormatInvertedBool(uint32 value)
  230. {
  231. return value == 0 ? "true" : "false";
  232. }