ff7_field_codegen.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  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. // TODO: Break into parts
  50. auto instruction = insts.begin();
  51. std::vector<std::pair<Function&, InstVec>> functions_with_bodies;
  52. for (
  53. auto function = _engine->_functions.begin();
  54. function != _engine->_functions.end();
  55. ++ function
  56. ){
  57. InstVec body;
  58. for (size_t i = 0; i < function->second.mNumInstructions; ++i, ++instruction)
  59. body.push_back(*instruction);
  60. functions_with_bodies.push_back(std::pair<Function&, InstVec> {function->second, body});
  61. }
  62. for (
  63. auto function = functions_with_bodies.begin();
  64. function != functions_with_bodies.end();
  65. ++ function
  66. ){
  67. onBeforeStartFunction(function->first);
  68. auto signature = constructFuncSignature(function->first);
  69. addOutputLine(signature, false, true);
  70. onStartFunction(function->first);
  71. // Comment with original instructions.
  72. std::unordered_map<uint32, InstVec> labels;
  73. for (
  74. auto instruction = function->second.begin();
  75. instruction != function->second.end();
  76. ++ instruction
  77. ){
  78. if ((*instruction)->isCondJump() || (*instruction)->isUncondJump()){
  79. auto targetAddr = (*instruction)->getDestAddress();
  80. auto label = labels.find(targetAddr);
  81. if (label == labels.end()) labels.insert({targetAddr, InstVec()});
  82. labels[targetAddr].push_back(*instruction);
  83. }
  84. }
  85. // Implemented instructions.
  86. for (
  87. auto instruction = function->second.begin();
  88. instruction != function->second.end();
  89. ++instruction
  90. ){
  91. auto label = labels.find((*instruction)->_address);
  92. if (label != labels.end()){
  93. bool needs_label = false;
  94. bool needs_new_line = false;
  95. for (auto origin = label->second.begin(); origin != label->second.end(); ++ origin){
  96. if ((*origin)->isCondJump()){
  97. addOutputLine("end", true, false);
  98. needs_new_line = true;
  99. }
  100. else needs_label = true;
  101. }
  102. if (needs_new_line) addOutputLine("");
  103. if (needs_label)
  104. addOutputLine((boost::format("::label_0x%1$X::") % label->first).str());
  105. }
  106. ValueStack stack;
  107. (*instruction)->processInst(function->first, stack, _engine, this);
  108. if ((*instruction)->isCondJump()){
  109. addOutputLine(
  110. (boost::format("if (%s) then") % stack.pop()->getString()).str(), false, true
  111. );
  112. // If there are no more instructions then ensure end is outputted.
  113. if (instruction + 1 == std::end(function->second)){
  114. addOutputLine("end", true, false);
  115. }
  116. }
  117. else if ((*instruction)->isUncondJump()){
  118. // If destination address is outside the functions, turn goto into a return.
  119. if ((*instruction)->getDestAddress() > function->first.mEndAddr){
  120. addOutputLine(
  121. "-- Overflowed jump to "
  122. + (boost::format("0x%1$X") % (*instruction)->getDestAddress()).str()
  123. + " (last address in function is "
  124. + (boost::format("0x%1$X)") % function->first.mEndAddr).str()
  125. );
  126. addOutputLine("do return 0 end");
  127. }
  128. else{
  129. addOutputLine(
  130. (boost::format("goto label_0x%1$X") % (*instruction)->getDestAddress()).str()
  131. );
  132. }
  133. }
  134. // Else, already output'd.
  135. }
  136. if (
  137. "return 0" != mLines.at(mLines.size() - 1)._line
  138. && "do return 0 end" != mLines.at(mLines.size() - 1)._line
  139. ){
  140. /*if (function->first._name == "Init"){
  141. addOutputLine("--do return 0 end -- INIT return, omit.", false, false);
  142. }
  143. addOutputLine("-- " + function->first._name + ": Missing original RET", false, false);
  144. addOutputLine("--LAST --" + mLines.at(mLines.size() - 1)._line + "--", false, false);*/
  145. addOutputLine("do return 0 end", false, false);
  146. }
  147. onEndFunction(function->first);
  148. }
  149. for (auto i = mLines.begin(); i != mLines.end(); ++i){
  150. if (i->_unindentBefore){
  151. assert(_indentLevel > 0);
  152. _indentLevel --;
  153. }
  154. _output << indentString(i->_line) << std::endl;
  155. if (i->_indentAfter) _indentLevel++;
  156. }
  157. }
  158. void FF7::FF7SimpleCodeGenerator::addOutputLine(std::string s, bool unindentBefore, bool indentAfter)
  159. {
  160. mLines.push_back(CodeLine(s, unindentBefore, indentAfter));
  161. }
  162. float FF7::FF7SimpleCodeGenerator::ScaleFactor() const
  163. {
  164. return static_cast<FF7::FF7FieldEngine*>(_engine)->ScaleFactor();
  165. }
  166. void FF7::FF7SimpleCodeGenerator::onBeforeStartFunction(const Function& func)
  167. {
  168. // Start class
  169. FunctionMetaData metaData(func._metadata);
  170. if (metaData.IsStart())
  171. {
  172. addOutputLine("EntityContainer[\"" + metaData.EntityName() + "\"] = {", false, true);
  173. if (metaData.CharacterId() != -1)
  174. {
  175. addOutputLine(metaData.EntityName() + " = nil,\n");
  176. }
  177. }
  178. const auto comment = mFormatter.FunctionComment(metaData.EntityName(), func._name);
  179. if (!comment.empty())
  180. {
  181. addOutputLine("-- " + comment);
  182. }
  183. }
  184. void FF7::FF7SimpleCodeGenerator::onStartFunction(const Function& func)
  185. {
  186. addOutputLine("--[[");
  187. for (const auto& inst : mInsts)
  188. {
  189. if (inst->_address >= func.mStartAddr && inst->_address <= func.mEndAddr)
  190. {
  191. std::stringstream output;
  192. output << inst;
  193. addOutputLine(output.str());
  194. }
  195. }
  196. addOutputLine("]]\n");
  197. if (func._name == "on_start" || func._name == "init")
  198. {
  199. addOutputLine("-- HACK ensure camera follows cloud, fix in engine properly later");
  200. addOutputLine("background2d:autoscroll_to_entity(entity_manager:get_entity(\"Cloud\"))");
  201. }
  202. }
  203. void FF7::FF7SimpleCodeGenerator::onEndFunction(const Function& func)
  204. {
  205. // End function
  206. addOutputLine("end,", true, false);
  207. // End class
  208. FunctionMetaData metaData(func._metadata);
  209. if (metaData.IsEnd())
  210. {
  211. addOutputLine("}\n\n\n", true, false);
  212. }
  213. else
  214. {
  215. addOutputLine("\n");
  216. }
  217. }
  218. std::string FF7::FF7SimpleCodeGenerator::constructFuncSignature(const Function &func)
  219. {
  220. // Generate name
  221. FunctionMetaData metaData(func._metadata);
  222. return mFormatter.FunctionName(metaData.EntityName(), func._name) + " = function(self)";
  223. }
  224. const std::string FF7::FF7CodeGeneratorHelpers::FormatInstructionNotImplemented(const std::string& entity, uint32 address, uint32 opcode)
  225. {
  226. return (boost::format("-- log:log(\"In entity \\\"%1%\\\", address 0x%2$08x: instruction 0x%3$04x not implemented\")") % entity % address % opcode).str();
  227. }
  228. const std::string FF7::FF7CodeGeneratorHelpers::FormatInstructionNotImplemented(const std::string& entity, uint32 address, const Instruction& instruction)
  229. {
  230. std::stringstream parameterList;
  231. for (auto i = instruction._params.begin(); i != instruction._params.end(); ++i)
  232. {
  233. if (i != instruction._params.begin())
  234. {
  235. parameterList << ", ";
  236. }
  237. parameterList << *i;
  238. }
  239. return (boost::format("-- log:log(\"In entity \\\"%1%\\\", address 0x%2$08x: instruction %3%(%4%) not implemented\")") % entity % address % instruction._name % parameterList.str()).str();
  240. }
  241. const std::string FF7::FF7CodeGeneratorHelpers::FormatBool(uint32 value)
  242. {
  243. return value == 0 ? "false" : "true";
  244. }
  245. const std::string FF7::FF7CodeGeneratorHelpers::FormatInvertedBool(uint32 value)
  246. {
  247. return value == 0 ? "true" : "false";
  248. }