ff7_field_codegen.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  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. bool end_needed = false;
  87. for (
  88. auto instruction = function->second.begin();
  89. instruction != function->second.end();
  90. ++instruction
  91. ){
  92. auto label = labels.find((*instruction)->_address);
  93. if (label != labels.end()){
  94. bool needs_label = false;
  95. bool needs_new_line = false;
  96. for (auto origin = label->second.begin(); origin != label->second.end(); ++ origin){
  97. if ((*origin)->isCondJump()){
  98. addOutputLine("end", true, false);
  99. needs_new_line = true;
  100. }
  101. else needs_label = true;
  102. }
  103. if (needs_new_line) addOutputLine("");
  104. if (needs_label)
  105. addOutputLine((boost::format("::label_0x%1$X::") % label->first).str());
  106. }
  107. ValueStack stack;
  108. (*instruction)->processInst(function->first, stack, _engine, this);
  109. if (end_needed){
  110. addOutputLine("end -- end if", true, false);
  111. end_needed = false;
  112. }
  113. if ((*instruction)->isCondJump()){
  114. addOutputLine(
  115. (boost::format("if (%s) then") % stack.pop()->getString()).str(), false, true
  116. );
  117. // If the next instruction is the last in the function, mark the next pass to
  118. // add an 'end' after the instruction to clode the if.
  119. if ((*(instruction + 1))->_address == (*(function->second.back()))._address)
  120. end_needed = true;
  121. }
  122. else if ((*instruction)->isUncondJump()){
  123. // If destination address is outside the functions, turn goto into a return.
  124. if ((*instruction)->getDestAddress() > function->first.mEndAddr){
  125. addOutputLine(
  126. "-- Overflowed jump to "
  127. + (boost::format("0x%1$X") % (*instruction)->getDestAddress()).str()
  128. + " (last address in function is "
  129. + (boost::format("0x%1$X)") % function->first.mEndAddr).str()
  130. );
  131. addOutputLine("do return 0 end");
  132. }
  133. else{
  134. addOutputLine(
  135. (boost::format("goto label_0x%1$X") % (*instruction)->getDestAddress()).str()
  136. );
  137. }
  138. }
  139. // Else, already output'd.
  140. }
  141. // Add missing return:
  142. if (
  143. "return 0" != mLines.at(mLines.size() - 1)._line
  144. && "do return 0 end" != mLines.at(mLines.size() - 1)._line
  145. ){
  146. addOutputLine("do return 0 end", false, false);
  147. }
  148. onEndFunction(function->first);
  149. }
  150. for (auto i = mLines.begin(); i != mLines.end(); ++i){
  151. if (i->_unindentBefore && _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. }