ff7_field_codegen.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  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. std::string last_instruction = "";
  83. for (auto instruction = function->second.begin(); instruction != function->second.end(); ++instruction)
  84. {
  85. auto label = labels.find((*instruction)->_address);
  86. if (label != labels.end())
  87. {
  88. bool needLabel = false, needNewline = false;
  89. for (auto origin = label->second.begin(); origin != label->second.end(); ++origin)
  90. {
  91. if ((*origin)->isCondJump())
  92. {
  93. addOutputLine("end", true, false);
  94. needNewline = true;
  95. }
  96. else
  97. {
  98. needLabel = true;
  99. }
  100. }
  101. if (needNewline)
  102. {
  103. addOutputLine("");
  104. }
  105. if (needLabel)
  106. {
  107. addOutputLine((boost::format("::label_0x%1$X::") % label->first).str());
  108. }
  109. }
  110. ValueStack stack;
  111. (*instruction)->processInst(function->first, stack, _engine, this);
  112. if ((*instruction)->isCondJump())
  113. {
  114. addOutputLine((boost::format("if (%s) then") % stack.pop()->getString()).str(), false, true);
  115. // If there are no more instructions then ensure end is outputted
  116. if (instruction + 1 == std::end(function->second))
  117. {
  118. addOutputLine("end", true, false);
  119. }
  120. }
  121. else if ((*instruction)->isUncondJump())
  122. {
  123. addOutputLine((boost::format("goto label_0x%1$X") % (*instruction)->getDestAddress()).str());
  124. }
  125. // else, was already output'd
  126. }
  127. if ("return 0" != mLines.at(mLines.size() - 1)._line)
  128. addOutputLine("return 0 -- Missing original return", false, false);
  129. onEndFunction(function->first);
  130. }
  131. for (auto i = mLines.begin(); i != mLines.end(); ++i)
  132. {
  133. if (i->_unindentBefore)
  134. {
  135. assert(_indentLevel > 0);
  136. _indentLevel--;
  137. }
  138. _output << indentString(i->_line) << std::endl;
  139. if (i->_indentAfter)
  140. {
  141. _indentLevel++;
  142. }
  143. }
  144. }
  145. void FF7::FF7SimpleCodeGenerator::addOutputLine(std::string s, bool unindentBefore, bool indentAfter)
  146. {
  147. mLines.push_back(CodeLine(s, unindentBefore, indentAfter));
  148. }
  149. float FF7::FF7SimpleCodeGenerator::ScaleFactor() const
  150. {
  151. return static_cast<FF7::FF7FieldEngine*>(_engine)->ScaleFactor();
  152. }
  153. void FF7::FF7SimpleCodeGenerator::onBeforeStartFunction(const Function& func)
  154. {
  155. // Start class
  156. FunctionMetaData metaData(func._metadata);
  157. if (metaData.IsStart())
  158. {
  159. addOutputLine("EntityContainer[ \"" + metaData.EntityName() + "\" ] = {", false, true);
  160. if (metaData.CharacterId() != -1)
  161. {
  162. addOutputLine(metaData.EntityName() + " = nil,\n");
  163. }
  164. }
  165. const auto comment = mFormatter.FunctionComment(metaData.EntityName(), func._name);
  166. if (!comment.empty())
  167. {
  168. addOutputLine("-- " + comment);
  169. }
  170. }
  171. void FF7::FF7SimpleCodeGenerator::onStartFunction(const Function& func)
  172. {
  173. addOutputLine("--[[");
  174. for (const auto& inst : mInsts)
  175. {
  176. if (inst->_address >= func.mStartAddr && inst->_address <= func.mEndAddr)
  177. {
  178. std::stringstream output;
  179. output << inst;
  180. addOutputLine(output.str());
  181. }
  182. }
  183. addOutputLine("]]\n");
  184. if (func._name == "on_start" || func._name == "init")
  185. {
  186. addOutputLine("-- HACK ensure camera follows cloud, fix in engine properly later");
  187. addOutputLine("background2d:autoscroll_to_entity(entity_manager:get_entity(\"Cloud\"))");
  188. }
  189. }
  190. void FF7::FF7SimpleCodeGenerator::onEndFunction(const Function& func)
  191. {
  192. // End function
  193. addOutputLine("end,", true, false);
  194. // End class
  195. FunctionMetaData metaData(func._metadata);
  196. if (metaData.IsEnd())
  197. {
  198. addOutputLine("}\n\n\n", true, false);
  199. }
  200. else
  201. {
  202. addOutputLine("\n");
  203. }
  204. }
  205. std::string FF7::FF7SimpleCodeGenerator::constructFuncSignature(const Function &func)
  206. {
  207. // Generate name
  208. FunctionMetaData metaData(func._metadata);
  209. return mFormatter.FunctionName(metaData.EntityName(), func._name) + " = function( self )";
  210. }
  211. const std::string FF7::FF7CodeGeneratorHelpers::FormatInstructionNotImplemented(const std::string& entity, uint32 address, uint32 opcode)
  212. {
  213. return (boost::format("-- log:log(\"In entity \\\"%1%\\\", address 0x%2$08x: instruction 0x%3$04x not implemented\")") % entity % address % opcode).str();
  214. }
  215. const std::string FF7::FF7CodeGeneratorHelpers::FormatInstructionNotImplemented(const std::string& entity, uint32 address, const Instruction& instruction)
  216. {
  217. std::stringstream parameterList;
  218. for (auto i = instruction._params.begin(); i != instruction._params.end(); ++i)
  219. {
  220. if (i != instruction._params.begin())
  221. {
  222. parameterList << ", ";
  223. }
  224. parameterList << *i;
  225. }
  226. return (boost::format("-- log:log(\"In entity \\\"%1%\\\", address 0x%2$08x: instruction %3%( %4% ) not implemented\")") % entity % address % instruction._name % parameterList.str()).str();
  227. }
  228. const std::string FF7::FF7CodeGeneratorHelpers::FormatBool(uint32 value)
  229. {
  230. return value == 0 ? "false" : "true";
  231. }
  232. const std::string FF7::FF7CodeGeneratorHelpers::FormatInvertedBool(uint32 value)
  233. {
  234. return value == 0 ? "true" : "false";
  235. }