Bladeren bron

Some more old SDUM code formatted and documented.

Iñigo Valentin 3 jaren geleden
bovenliggende
commit
0d189388c5

+ 2 - 2
V-Gears-Installer/CMakeLists.txt

@@ -23,7 +23,7 @@ set(HEADER_FILES
     include/common/Logger.h
     include/decompiler/sudm.h
     include/decompiler/decompiler_codegen.h
-    include/decompiler/control_flow.h
+    include/decompiler/ControlFlow.h
     include/decompiler/decompiler_disassembler.h
     include/decompiler/decompiler_engine.h
     include/decompiler/graph.h
@@ -84,7 +84,7 @@ set(SOURCE_FILES
     src/VGearsUtility.cpp
     src/decompiler/sudm.cpp
     src/decompiler/decompiler_codegen.cpp
-    src/decompiler/control_flow.cpp
+    src/decompiler/ControlFlow.cpp
     src/decompiler/decompiler_disassembler.cpp
     src/decompiler/graph.cpp
     src/decompiler/instruction.cpp

+ 207 - 0
V-Gears-Installer/include/decompiler/ControlFlow.h

@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2022 The V-Gears Team
+ *
+ * This file is part of V-Gears
+ *
+ * V-Gears is free software: you can redistribute it and/or modify it under
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation, version 3.0 (GPLv3) of the License.
+ *
+ * V-Gears is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#pragma once
+
+#include "graph.h"
+#include "decompiler_engine.h"
+
+/**
+ * Class for doing code flow analysis.
+ */
+class ControlFlow {
+
+    public:
+
+        /**
+         * Constructor for the control flow graph.
+         *
+         * @param insts[in] The instructions to analyze control flow for.
+         * @param engine[in] Pointer to the Engine used for the script.
+         */
+        ControlFlow(InstVec& insts, Engine& engine);
+
+        /**
+         * Copy constructor disabled.
+         *
+         * @param control_flow[in] The control flow to copy.
+         */
+        ControlFlow(const ControlFlow& control_flow) = delete;
+
+        /**
+         * Copy constructor disabled.
+         *
+         * @param control_flow[in] The control flow to copy.
+         */
+        ControlFlow& operator = (const ControlFlow& control_flow) = delete;
+
+        /**
+         * Retrieves the current control flow graph.
+         *
+         * @returns The current control flow graph.
+         */
+        const Graph& GetGraph() const;
+
+        /**
+         * Creates groups suitable for a stack-based machine.
+         *
+         * Before group creation, the expected stack level for each
+         * instruction is determined. After group creation, short-circuit
+         * detection is applied to the groups.
+         */
+        void CreateGroups();
+
+        /**
+         * Performs control flow analysis.
+         *
+         * The constructs are detected in the following order: do-while,
+         * while, break, continue, if/else.
+         *
+         * @returns The control flow graph after analysis.
+         */
+        const Graph& Analyze();
+
+    private:
+
+        /**
+         * The control flow graph.
+         */
+        Graph graph_;
+
+        /**
+         * The engine used for the script.
+         */
+        Engine& engine_;
+
+        /**
+         * The instructions being analyzed.
+         */
+        InstVec &insts_;
+
+        /**
+         * Map of addresses and vertices.
+         */
+        std::map<uint32, GraphVertex> addr_map_;
+
+        /**
+         * Finds a graph vertex through an instruction.
+         *
+         * @param inst[in] The instruction to find the vertex for.
+         */
+        GraphVertex Find(const InstPtr inst);
+
+        /**
+         * Finds a graph vertex through an instruction iterator.
+         *
+         * @param it[in] The iterator to find the vertex for.
+         */
+        GraphVertex Find(ConstInstIterator it);
+
+        /**
+         * Finds a graph vertex through an address.
+         *
+         * @param address[in] The address to find the vertex for.
+         */
+        GraphVertex Find(uint32 address);
+
+        /**
+         * Merges two graph vertices.
+         *
+         * graph_2 will be merged into graph_1.
+         *
+         * @param g1[in|out] The first vertex to merge.
+         * @param g2[in] The second vertex to merge.
+         */
+        void Merge(GraphVertex graph_1, GraphVertex graph_2);
+
+        /**
+         * Sets the stack level for all instructions, using depth-first search.
+         *
+         * @param graph[in] The GraphVertex to search from.
+         * @param level[in] The stack level when g is reached.
+         */
+        void SetStackLevel(GraphVertex graph, int level);
+
+        /**
+         * Merged groups that are part of the same short-circuited condition.
+         */
+        void DetectShortCircuit();
+
+        /**
+         * Detects while blocks.
+         *
+         * Do-while detection must be completed before running this method.
+         */
+        void DetectWhile();
+
+        /**
+         * Detects do-while blocks.
+         */
+        void DetectDoWhile();
+
+        /**
+         * Detects break statements.
+         *
+         * Do-while and while detection must be completed before running this
+         * method.
+         */
+        void DetectBreak();
+
+        /**
+         * Detects continue statements.
+         *
+         * Do-while and while detection must be completed before running this
+         * method.
+         */
+        void DetectContinue();
+
+        /**
+         * Checks if a candidate break/continue goes to the closest loop.
+         *
+         * @param group[in] The group containing the candidate break/continue.
+         * @param condition_group[in] The group containing the respective loop
+         * condition.
+         * @returns True if the validation succeeded, false if it did not.
+         */
+        bool ValidateBreakOrContinue(GroupPtr group, GroupPtr condition_group);
+
+        /**
+         * Detects if blocks.
+         *
+         * Must be performed after break and continue detection.
+         */
+        void DetectIf();
+
+        /**
+         * Detects else blocks.
+         *
+         * Must be performed after if detection.
+         */
+        void DetectElse();
+
+        /**
+         * Checks if a candidate else block will cross block boundaries.
+         *
+         * @param if_group[in] The group containing the if this else candidate
+         * is associated with.
+         * @param start[in] The group containing the start of the else.
+         * @param end[in] The group immediately after the group ending the
+         * else.
+         * @returns True if the validation succeeded, false if it did not.
+         */
+        bool ValidateElseBlock(GroupPtr if_group, GroupPtr start, GroupPtr end);
+
+};
+

+ 0 - 169
V-Gears-Installer/include/decompiler/control_flow.h

@@ -1,169 +0,0 @@
-/* ScummVM Tools
- *
- * ScummVM Tools is the legal property of its developers, whose
- * names are too numerous to list here. Please refer to the
- * COPYRIGHT file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#ifndef DEC_CONTROL_FLOW_H
-#define DEC_CONTROL_FLOW_H
-
-#include "graph.h"
-#include "decompiler_engine.h"
-
-/**
- * Class for doing code flow analysis.
- */
-class ControlFlow {
-private:
-	Graph _g;                               ///< The control flow graph.
-	Engine& mEngine;                        ///< Pointer to the Engine used for the script.
-	InstVec &mInsts;                  ///< The instructions being analyzed
-	std::map<uint32, GraphVertex> _addrMap; ///< Map between addresses and vertices.
-
-	/**
-	 * Finds a graph vertex through an instruction.
-	 *
-	 * @param inst The instruction to find the vertex for.
-	 */
-	GraphVertex find(const InstPtr inst);
-
-	/**
-	 * Finds a graph vertex through an instruction iterator.
-	 *
-	 * @param it The iterator to find the vertex for.
-	 */
-	GraphVertex find(ConstInstIterator it);
-
-	/**
-	 * Finds a graph vertex through an address.
-	 *
-	 * @param address The address to find the vertex for.
-	 */
-	GraphVertex find(uint32 address);
-
-	/**
-	 * Merges two graph vertices. g2 will be merged into g1.
-	 *
-	 * @param g1 The first vertex to merge.
-	 * @param g2 The second vertex to merge.
-	 */
-	void merge(GraphVertex g1, GraphVertex g2);
-
-	/**
-	 * Sets the stack level for all instructions, using depth-first search.
-	 *
-	 * @param g     The GraphVertex to search from.
-	 * @param level The stack level when g is reached.
-	 */
-	void setStackLevel(GraphVertex g, int level);
-
-	/**
-	 * Merged groups that are part of the same short-circuited condition check.
-	 */
-	void detectShortCircuit();
-
-	/**
-	 * Detects while blocks.
-	 * Do-while detection must be completed before running this method.
-	 */
-	void detectWhile();
-
-	/**
-	 * Detects do-while blocks.
-	 */
-	void detectDoWhile();
-
-	/**
-	 * Detects break statements.
-	 * Do-while and while detection must be completed before running this method.
-	 */
-	void detectBreak();
-
-	/**
-	 * Detects continue statements.
-	 * Do-while and while detection must be completed before running this method.
-	 */
-	void detectContinue();
-
-	/**
-	 * Checks if a candidate break/continue goes to the closest loop.
-	 *
-	 * @param gr     The group containing the candidate break/continue.
-	 * @param condGr The group containing the respective loop condition.
-	 * @returns True if the validation succeeded, false if it did not.
-	 */
-	bool validateBreakOrContinue(GroupPtr gr, GroupPtr condGr);
-
-	/**
-	 * Detects if blocks.
-	 * Must be performed after break and continue detection.
-	 */
-	void detectIf();
-
-	/**
-	 * Detects else blocks.
-	 * Must be performed after if detection.
-	 */
-	void detectElse();
-
-	/**
-	 * Checks if a candidate else block will cross block boundaries.
-	 *
-	 * @param ifGroup The group containing the if this else candidate is associated with.
-	 * @param start   The group containing the start of the else.
-	 * @param end     The group immediately after the group ending the else.
-	 * @returns True if the validation succeeded, false if it did not.
-	 */
-	bool validateElseBlock(GroupPtr ifGroup, GroupPtr start, GroupPtr end);
-
-public:
-    ControlFlow(const ControlFlow&) = delete;
-    ControlFlow& operator = (const ControlFlow&) = delete;
-
-	/**
-	 * Gets the current control flow graph.
-	 *
-	 * @returns The current control flow graph.
-	 */
-	const Graph &getGraph() const { return _g; };
-
-	/**
-	 * Constructor for the control flow graph.
-	 *
-	 * @param insts  std::vector containing the instructions to analyze control flow for.
-	 * @param engine Pointer to the Engine used for the script.
-	 */
-	ControlFlow(InstVec& insts, Engine& engine);
-
-	/**
-	 * Creates groups suitable for a stack-based machine.
-	 * Before group creation, the expected stack level for each instruction is determined.
-	 * After group creation, short-circuit detection is applied to the groups.
-	 */
-	void createGroups();
-
-	/**
-	 * Performs control flow analysis.
-	 * The constructs are detected in the following order: do-while, while, break, continue, if/else.
-	 *
-	 * @returns The control flow graph after analysis.
-	 */
-	const Graph &analyze();
-};
-
-#endif

+ 1 - 1
V-Gears-Installer/include/decompiler/test/cfg_test.cpp

@@ -19,12 +19,12 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
-#include "decompiler/control_flow.h"
 #include "decompiler/decompiler_disassembler.h"
 #include "decompiler/graph.h"
 #include "decompiler/scummv6/engine.h"
 #include <gmock/gmock.h>
 #include <vector>
+#include "../ControlFlow.h"
 
 #define GET(vertex) (boost::get(boost::vertex_name, g, vertex))
 

+ 2 - 1
V-Gears-Installer/include/decompiler/test/codegen.cpp

@@ -20,13 +20,14 @@
  */
 
 
-#include "decompiler/control_flow.h"
 #include "decompiler/decompiler_disassembler.h"
 #include "decompiler/graph.h"
 #include "decompiler/decompiler_codegen.h"
 #include "decompiler/scummv6/engine.h"
 
 #include <vector>
+
+#include "../ControlFlow.h"
 #define GET(vertex) (boost::get(boost::vertex_name, g, vertex))
 
 #include <streambuf>

+ 2 - 1
V-Gears-Installer/include/decompiler/test/ff7_field_all_opcodes_disassembler_test.cpp

@@ -1,8 +1,9 @@
 #include <gmock/gmock.h>
+
+#include "../ControlFlow.h"
 #include "decompiler/ff7_field/ff7_field_disassembler.h"
 #include "decompiler/ff7_field/ff7_field_engine.h"
 #include "decompiler/ff7_field/ff7_field_codegen.h"
-#include "control_flow.h"
 #include "util.h"
 #include "ff7_field_dummy_formatter.h"
 

+ 2 - 1
V-Gears-Installer/include/decompiler/test/ff7_field_control_flow_test.cpp

@@ -1,8 +1,9 @@
 #include <gmock/gmock.h>
+
+#include "../ControlFlow.h"
 #include "decompiler/ff7_field/ff7_field_disassembler.h"
 #include "decompiler/ff7_field/ff7_field_engine.h"
 #include "decompiler/ff7_field/ff7_field_codegen.h"
-#include "control_flow.h"
 #include "util.h"
 #include "ff7_field_dummy_formatter.h"
 

+ 1 - 1
V-Gears-Installer/include/decompiler/test/ff7_field_disasm_all_opcodes_by_category_test.cpp

@@ -1,10 +1,10 @@
 #include <gmock/gmock.h>
 
 #include "../../common/Lzs.h"
+#include "../ControlFlow.h"
 #include "decompiler/ff7_field/ff7_field_disassembler.h"
 #include "decompiler/ff7_field/ff7_field_engine.h"
 #include "decompiler/ff7_field/ff7_field_codegen.h"
-#include "control_flow.h"
 #include "util.h"
 #include "ff7_field_dummy_formatter.h"
 

+ 1 - 1
V-Gears-Installer/include/decompiler/test/main.cpp

@@ -1,6 +1,7 @@
 #include <gmock/gmock.h>
 
 #include "../../common/Lzs.h"
+#include "../ControlFlow.h"
 #include "decompiler/ff7_field/ff7_field_disassembler.h"
 #include "decompiler/ff7_field/ff7_field_engine.h"
 #include "decompiler/ff7_field/ff7_field_codegen.h"
@@ -8,7 +9,6 @@
 #include "decompiler/ff7_world/ff7_world_disassembler.h"
 #include "decompiler/ff7_world/ff7_world_engine.h"
 
-#include "control_flow.h"
 #include "util.h"
 #include "graph.h"
 #include "sudm.h"

+ 597 - 0
V-Gears-Installer/src/decompiler/ControlFlow.cpp

@@ -0,0 +1,597 @@
+/*
+ * Copyright (C) 2022 The V-Gears Team
+ *
+ * This file is part of V-Gears
+ *
+ * V-Gears is free software: you can redistribute it and/or modify it under
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation, version 3.0 (GPLv3) of the License.
+ *
+ * V-Gears is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <algorithm>
+#include <iostream>
+#include <set>
+#include <boost/format.hpp>
+#include "decompiler/ControlFlow.h"
+#include "decompiler/stack.h"
+
+/**
+ * Adds a vertex to a group.
+ *
+ * @param vertex[in] Vertex to add.
+ * @param group[in] Group to add the vertex to.
+ */
+#define PUT(vertex, group) boost::put(boost::vertex_name, graph_, vertex, group);
+
+/**
+ * Adds an edge to the graph.
+ *
+ * @param edge[in] The edge to add.
+ * @param is_jump[in] Indicates if the edge is a jump.
+ */
+#define PUT_EDGE(edge, is_jump) boost::put(boost::edge_attribute, graph_, edge, is_jump);
+
+/**
+ * Adds a vertex to the graph.
+ *
+ * @param vertex[in] The vertex to add.
+ * @param id[in] The vertext index.
+ */
+#define PUT_ID(vertex, id) boost::put(boost::vertex_index, graph_, vertex, id);
+
+/**
+ * Retrieves a vertex.
+ *
+ * @param vertex[in] The vertex.
+ * @return The retrieved vertex.
+ */
+#define GET(vertex) (boost::get(boost::vertex_name, graph_, vertex))
+
+/**
+ * Retrieves an edge.
+ *
+ * @param edge[in] The edge.
+ * @return The retrieved edge.
+ */
+#define GET_EDGE(edge) (boost::get(boost::edge_attribute, graph_, edge))
+
+ControlFlow::ControlFlow(InstVec& insts, Engine& engine): insts_(insts),engine_(engine){
+
+    // Automatically add a function if we're not supposed to look for more functions
+    // and no functions are defined.
+    // This avoids a special case for when no real functions exist in the script.
+    if (engine_._functions.empty()){
+        engine_._functions[(*insts.begin())->_address]= Function(
+          (*insts.begin())->_address, (insts.back())->_address
+        );
+    }
+    GroupPtr prev = NULL;
+    int id = 0;
+    // Create vertices.
+    for (InstIterator it = insts.begin(); it != insts.end(); ++ it){
+        GraphVertex cur = boost::add_vertex(graph_);
+        addr_map_[(*it)->_address] = cur;
+        PUT(cur, new Group(cur, it, it, prev));
+        PUT_ID(cur, id);
+        id ++;
+        // Add reference to vertex if function starts here.
+        if (engine_._functions.find((*it)->_address) != engine_._functions.end())
+            engine_._functions[(*it)->_address]._v = cur;
+        prev = GET(cur);
+    }
+    // Add regular edges.
+    FuncMap::iterator fn;
+    GraphVertex last ={};
+    bool add_edge = false;
+    prev = NULL;
+    for (InstIterator it = insts.begin(); it != insts.end(); ++it){
+        if (engine_._functions.find((*it)->_address) != engine_._functions.end()) add_edge = false;
+        GraphVertex cur = Find(it);
+        if (add_edge){
+            GraphEdge e = boost::add_edge(last, cur, graph_).first;
+            PUT_EDGE(e, false);
+        }
+        last = cur;
+        add_edge = !((*it)->IsUncondJump() || (*it)->isReturn());
+        prev = GET(cur);
+
+    }
+    // Add jump edges.
+    for (InstIterator it = insts.begin(); it != insts.end(); ++ it){
+        if ((*it)->isJump()){
+            GraphEdge e = boost::add_edge(Find(it), Find((*it)->GetDestAddress()), graph_).first;
+            PUT_EDGE(e, true);
+        }
+    }
+}
+
+const Graph& ControlFlow::GetGraph() const{return graph_;}
+
+GraphVertex ControlFlow::Find(const InstPtr inst){return addr_map_[inst->_address];}
+
+GraphVertex ControlFlow::Find(ConstInstIterator it){return addr_map_[(*it)->_address];}
+
+GraphVertex ControlFlow::Find(uint32 address){
+    std::map<uint32, GraphVertex>::iterator it = addr_map_.find(address);
+    if (it == addr_map_.end()){
+        std::cerr << "Request for instruction at unknown address "
+          << boost::format("0x%08x") % address << std::endl;
+    }
+    return it->second;
+}
+
+void ControlFlow::Merge(GraphVertex graph_1, GraphVertex graph_2){
+    // Update property.
+    GroupPtr gr1 = GET(graph_1);
+    GroupPtr gr2 = GET(graph_2);
+    gr1->end_ = gr2->end_;
+    PUT(graph_1, gr1);
+    // Update address map.
+    ConstInstIterator it = gr2->start_;
+    do{
+        addr_map_[(*it)->_address] = graph_1;
+        ++ it;
+    } while (gr2->start_ != gr2->end_ && it != gr2->end_);
+    // Add outgoing edges from graph_2.
+    OutEdgeRange r = boost::out_edges(graph_2, graph_);
+    for (OutEdgeIterator e = r.first; e != r.second; ++e){
+        GraphEdge newE = boost::add_edge(graph_1, boost::target(*e, graph_), graph_).first;
+        PUT_EDGE(newE, GET_EDGE(*e));
+    }
+    // Update _next pointer.
+    gr1->_next = gr2->_next;
+    if (gr2->_next != NULL) gr2->_next->_prev = gr2->_prev;
+    // Remove edges to/from graph_2
+    boost::clear_vertex(graph_2, graph_);
+    // Remove vertex.
+    boost::remove_vertex(graph_2, graph_);
+}
+
+typedef std::pair<GraphVertex, int> LevelEntry;
+
+void ControlFlow::SetStackLevel(GraphVertex graph, int level){
+    Stack<LevelEntry> level_stack;
+    std::set<GraphVertex> seen;
+    level_stack.push(LevelEntry(graph, level));
+    seen.insert(graph);
+    while (!level_stack.empty()){
+        LevelEntry e = level_stack.pop();
+        GroupPtr gr = GET(e.first);
+        if (gr->_stackLevel != -1){
+            if (gr->_stackLevel != e.second)
+                std::cerr << boost::format(
+                  "WARNING: Inconsistency in expected stack level for instruction "
+                  "at address 0x%08x (current: %d, requested: %d)\n"
+                ) % (*gr->start_)->_address % gr->_stackLevel % e.second;
+            continue;
+        }
+        gr->_stackLevel = e.second;
+        OutEdgeRange r = boost::out_edges(e.first, graph_);
+        for (OutEdgeIterator oe = r.first; oe != r.second; ++ oe){
+            GraphVertex target = boost::target(*oe, graph_);
+            if (seen.find(target) == seen.end()){
+                level_stack.push(LevelEntry(target, e.second + (*gr->start_)->_stackChange));
+                seen.insert(target);
+            }
+        }
+    }
+}
+
+void ControlFlow::CreateGroups(){
+    if (
+      !engine_._functions.empty() && GET(engine_._functions.begin()->second._v)->_stackLevel != -1
+    ){
+        return;
+    }
+
+    for (FuncMap::iterator fn = engine_._functions.begin(); fn != engine_._functions.end(); ++ fn)
+        SetStackLevel(fn->second._v, 0);
+    ConstInstIterator cur_inst, next_inst;
+    next_inst = insts_.begin();
+    next_inst++;
+    int stack_level = 0;
+    int expected_stack_level = 0;
+    for (cur_inst = insts_.begin(); next_inst != insts_.end(); ++ cur_inst, ++ next_inst){
+        GraphVertex cur = Find(cur_inst);
+        GraphVertex next = Find(next_inst);
+        GroupPtr group_cur = GET(cur);
+        GroupPtr group_next = GET(next);
+        // Don't process unreachable code.
+        if (group_cur->_stackLevel < 0){
+            stack_level = group_next->_stackLevel;
+            continue;
+        }
+        expected_stack_level = group_cur->_stackLevel;
+        // If expected stack level decreases in next vertex, then
+        // use next vertex level as expected level.
+        if (expected_stack_level > group_next->_stackLevel && group_next->_stackLevel >= 0){
+            expected_stack_level = group_next->_stackLevel;
+            // Also set the stack level of the current group
+            // to remember that we expect it to be lower.
+            group_cur->_stackLevel = expected_stack_level;
+        }
+        stack_level += (*cur_inst)->_stackChange;
+        // For stack operations, the new stack level becomes the
+        // expected stack level starting from the next group.
+        if ((*cur_inst)->isStackOp()){
+            expected_stack_level = stack_level;
+            group_next->_stackLevel = stack_level;
+        }
+        // Group ends after a jump.
+        if ((*cur_inst)->isJump()){
+            stack_level = group_next->_stackLevel;
+            continue;
+        }
+        // Group ends with a return.
+        if ((*cur_inst)->isReturn()){
+            stack_level = group_next->_stackLevel;
+            continue;
+        }
+        // Group ends before target of a jump.
+        if (in_degree(next, graph_) != 1){
+            stack_level = group_next->_stackLevel;
+            continue;
+        }
+        // This part is only relevant if we use the stack level.
+        if (!engine_.UsePureGrouping()){
+            // If group has no instructions with stack effect >= 0, don't merge on balanced stack.
+            bool forceMerge = true;
+            ConstInstIterator it = group_cur->start_;
+            do{
+                if ((*it)->_stackChange >= 0) forceMerge = false;
+                ++ it;
+            } while (group_cur->start_ != group_cur->end_ && it != group_cur->end_);
+            // Group ends when stack is balanced, unless just before conditional jump.
+            if (stack_level == expected_stack_level && !forceMerge && !(*next_inst)->isCondJump())
+                continue;
+        }
+        // All checks passed, merge groups
+        Merge(cur, next);
+    }
+
+    // FIXME: The short-circuit detection is disabled because short-circuited
+    // groups require some special handling in the code generation. It's not
+    // entirely clear how to handle it properly, though: It has to be deduced
+    // which effect is created by the conditional jumps in the middle of a
+    // block, which seems to get fairly complex when there are multiple groups
+    // that are merged by the short-circuit detection.
+    //detectShortCircuit();
+}
+
+void ControlFlow::DetectShortCircuit(){
+    ConstInstIterator last_inst = insts_.end();
+    -- last_inst;
+    GraphVertex cur = Find(last_inst);
+    GroupPtr gr = GET(cur);
+    while (gr->_prev != NULL){
+        bool do_merge = false;
+        cur = Find(gr->start_);
+        GraphVertex prev = Find(gr->_prev->start_);
+        // Block is candidate for short-circuit merging if it and the
+        // preceding block both end with conditional jumps.
+        if (out_degree(cur, graph_) == 2 && out_degree(prev, graph_) == 2){
+            do_merge = true;
+            OutEdgeRange range_cur = boost::out_edges(cur, graph_);
+            std::vector<GraphVertex> succs;
+            // Find possible target vertices.
+            for (OutEdgeIterator it = range_cur.first; it != range_cur.second; ++ it)
+                succs.push_back(boost::target(*it, graph_));
+            // Check if vertex would add new targets - if yes, don't merge.
+            OutEdgeRange range_prev = boost::out_edges(prev, graph_);
+            for (OutEdgeIterator it = range_prev.first; it != range_prev.second; ++ it){
+                GraphVertex target = boost::target(*it, graph_);
+                do_merge &= (
+                  std::find(succs.begin(), succs.end(), target) != succs.end() || target == cur
+                );
+            }
+            if (do_merge){
+                gr = gr->_prev;
+                Merge(prev, cur);
+                continue;
+            }
+        }
+        gr = gr->_prev;
+    }
+}
+
+const Graph &ControlFlow::Analyze(){
+    DetectDoWhile();
+    DetectWhile();
+    DetectBreak();
+    DetectContinue();
+    DetectIf();
+    DetectElse();
+    return graph_;
+}
+
+void ControlFlow::DetectWhile(){
+    VertexRange vertex_range = boost::vertices(graph_);
+    for (VertexIterator v = vertex_range.first; v != vertex_range.second; ++ v){
+        GroupPtr gr = GET(*v);
+        // Undetermined block that ends with conditional jump.
+        if (out_degree(*v, graph_) == 2 && gr->_type == kNormalGroupType){
+            InEdgeRange ier = boost::in_edges(*v, graph_);
+            bool is_while = false;
+            for (InEdgeIterator e = ier.first; e != ier.second; ++e){
+                GroupPtr source_gr = GET(boost::source(*e, graph_));
+                // Block has ingoing edge from block later in the
+                // code that isn't a do-while condition.
+                if (
+                  (*source_gr->start_)->_address > (*gr->start_)->_address
+                  && source_gr->_type != kDoWhileCondGroupType
+                ){
+                    is_while = true;
+                }
+            }
+            if (is_while) gr->_type = kWhileCondGroupType;
+        }
+    }
+}
+
+void ControlFlow::DetectDoWhile(){
+    VertexRange vertex_range = boost::vertices(graph_);
+    for (VertexIterator v = vertex_range.first; v != vertex_range.second; ++ v){
+        GroupPtr gr = GET(*v);
+        // Undetermined block that ends with conditional jump...
+        if (out_degree(*v, graph_) == 2 && gr->_type == kNormalGroupType){
+            OutEdgeRange oer = boost::out_edges(*v, graph_);
+            for (OutEdgeIterator e = oer.first; e != oer.second; ++e){
+                GroupPtr target_gr = GET(boost::target(*e, graph_));
+                // ...to earlier in code.
+                if ((*target_gr->start_)->_address < (*gr->start_)->_address)
+                    gr->_type = kDoWhileCondGroupType;
+            }
+        }
+    }
+}
+
+void ControlFlow::DetectBreak(){
+    VertexRange vertex_range = boost::vertices(graph_);
+    for (VertexIterator v = vertex_range.first; v != vertex_range.second; ++ v){
+        GroupPtr gr = GET(*v);
+        // Undetermined block with unconditional jump...
+        if (
+          gr->_type == kNormalGroupType
+          && ((*gr->end_)->IsUncondJump())
+          && out_degree(*v, graph_) == 1
+        ){
+            OutEdgeIterator oe = boost::out_edges(*v, graph_).first;
+            GraphVertex target = boost::target(*oe, graph_);
+            GroupPtr target_gr = GET(target);
+            // ...to somewhere later in the code...
+            if ((*gr->start_)->_address >= (*target_gr->start_)->_address) continue;
+            InEdgeRange ier = boost::in_edges(target, graph_);
+            for (InEdgeIterator ie = ier.first; ie != ier.second; ++ ie){
+                GroupPtr source_gr = GET(boost::source(*ie, graph_));
+                // ...to block immediately after a do-while condition,
+                // or to jump target of a while condition.
+                if (
+                  (target_gr->_prev == source_gr && source_gr->_type == kDoWhileCondGroupType)
+                  || source_gr->_type == kWhileCondGroupType
+                ){
+                    if (ValidateBreakOrContinue(gr, source_gr)) gr->_type = kBreakGroupType;
+                }
+            }
+        }
+    }
+}
+
+void ControlFlow::DetectContinue(){
+    VertexRange vertex_range = boost::vertices(graph_);
+    for (VertexIterator v = vertex_range.first; v != vertex_range.second; ++ v){
+        GroupPtr gr = GET(*v);
+        // Undetermined block with unconditional jump...
+        if (
+          gr->_type == kNormalGroupType
+          && ((*gr->end_)->IsUncondJump())
+          && out_degree(*v, graph_) == 1
+        ){
+            OutEdgeIterator oe = boost::out_edges(*v, graph_).first;
+            GraphVertex target = boost::target(*oe, graph_);
+            GroupPtr target_gr = GET(target);
+            // ...to a while or do-while condition...
+            if (
+              target_gr->_type == kWhileCondGroupType || target_gr->_type == kDoWhileCondGroupType
+            ){
+                bool is_continue = true;
+                // ...unless...
+                OutEdgeRange toer = boost::out_edges(target, graph_);
+                bool after_jump_jargets = true;
+                for (OutEdgeIterator toe = toer.first; toe != toer.second; ++ toe){
+                    // ...it is targeting a while condition which jumps to the next sequential group
+                    if (
+                      target_gr->_type == kWhileCondGroupType
+                      && GET(boost::target(*toe, graph_)) == gr->_next
+                    ){
+                        is_continue = false;
+                    }
+                    // ...or the instruction is placed after all jump targets from condition.
+                    if (
+                      (*GET(boost::target(*toe, graph_))->start_)->_address
+                        > (*gr->start_)->_address
+                    ){
+                        after_jump_jargets = false;
+                    }
+                }
+                if (after_jump_jargets) is_continue = false;
+
+                if (is_continue && ValidateBreakOrContinue(gr, target_gr))
+                    gr->_type = kContinueGroupType;
+            }
+        }
+    }
+}
+
+bool ControlFlow::ValidateBreakOrContinue(GroupPtr group, GroupPtr condition_group){
+    GroupPtr from;
+    GroupPtr to;
+    GroupPtr cursor;
+    if (condition_group->_type == kDoWhileCondGroupType){
+        to = condition_group;
+        from = group;
+    }
+    else{
+        to = group;
+        from = condition_group->_next;
+    }
+    GroupType ogt = (
+      condition_group->_type == kDoWhileCondGroupType ? kWhileCondGroupType : kDoWhileCondGroupType
+    );
+    // Verify that destination deals with innermost while/do-while.
+    for (cursor = from; cursor->_next != NULL && cursor != to; cursor = cursor->_next){
+        if (cursor->_type == condition_group->_type){
+            OutEdgeRange oer_validate = boost::out_edges(Find(cursor->start_), graph_);
+            for (
+              OutEdgeIterator oe_validate = oer_validate.first;
+              oe_validate != oer_validate.second;
+              ++ oe_validate
+            ){
+                GraphVertex v_validate = boost::target(*oe_validate, graph_);
+                GroupPtr g_validate = GET(v_validate);
+                // For all other loops of same type found in range,
+                // all targets must fall within that range.
+                if (
+                  (*g_validate->start_)->_address < (*from->start_)->_address
+                  || (*g_validate->start_)->_address > (*to->start_)->_address
+                ){
+                    return false;
+                }
+                InEdgeRange ier_validate = boost::in_edges(v_validate, graph_);
+                for (
+                  InEdgeIterator ie_validate = ier_validate.first;
+                  ie_validate != ier_validate.second;
+                  ++ ie_validate
+                ){
+                    GroupPtr ig_validate = GET(boost::source(*ie_validate, graph_));
+                    // All loops of other type going into range must be placed within range.
+                    if (
+                      ig_validate->_type == ogt
+                      && (
+                        (*ig_validate->start_)->_address < (*from->start_)->_address
+                        || (*ig_validate->start_)->_address > (*to->start_)->_address
+                      )
+                    ){
+                        return false;
+                    }
+                }
+            }
+        }
+    }
+    return true;
+}
+
+void ControlFlow::DetectIf(){
+    VertexRange vr = boost::vertices(graph_);
+    for (VertexIterator v = vr.first; v != vr.second; ++v){
+        GroupPtr gr = GET(*v);
+        // If: Undetermined block with conditional jump.
+        if (gr->_type == kNormalGroupType && ((*gr->end_)->isCondJump()))
+            gr->_type = kIfCondGroupType;
+    }
+}
+
+void ControlFlow::DetectElse(){
+    VertexRange vr = boost::vertices(graph_);
+    for (VertexIterator v = vr.first; v != vr.second; ++v){
+        GroupPtr gr = GET(*v);
+        if (gr->_type == kIfCondGroupType){
+            OutEdgeRange oer = boost::out_edges(*v, graph_);
+            GraphVertex target;
+            uint32 max_address = 0;
+            GroupPtr target_gr;
+            // Find jump target.
+            for (OutEdgeIterator oe = oer.first; oe != oer.second; ++ oe){
+                target_gr = GET(boost::target(*oe, graph_));
+                if ((*target_gr->start_)->_address > max_address){
+                    target = boost::target(*oe, graph_);
+                    max_address = (*target_gr->start_)->_address;
+                }
+            }
+            target_gr = GET(target);
+            // Else: Jump target of if immediately preceded by an unconditional jump...
+            if (!(*target_gr->_prev->end_)->IsUncondJump()) continue;
+            // ...which is not a break or a continue...
+            if (
+              target_gr->_prev->_type == kContinueGroupType
+              || target_gr->_prev->_type == kBreakGroupType
+            ){
+                continue;
+            }
+            // ...to later in the code.
+            OutEdgeIterator toe = boost::out_edges(
+              Find((*target_gr->_prev->start_)->_address), graph_
+            ).first;
+            GroupPtr target_target_gr = GET(boost::target(*toe, graph_));
+            if ((*target_target_gr->start_)->_address > (*target_gr->end_)->_address){
+                if (ValidateElseBlock(gr, target_gr, target_target_gr)){
+                    target_gr->_startElse = true;
+                    target_target_gr->_prev->_endElse.push_back(target_gr.get());
+                }
+            }
+        }
+    }
+}
+
+bool ControlFlow::ValidateElseBlock(GroupPtr if_group, GroupPtr start, GroupPtr end){
+    for (GroupPtr cursor = start; cursor != end; cursor = cursor->_next){
+        if (
+          cursor->_type == kIfCondGroupType
+          || cursor->_type == kWhileCondGroupType
+          || cursor->_type == kDoWhileCondGroupType
+        ){
+            // Validate outgoing edges of conditions.
+            OutEdgeRange oer = boost::out_edges(Find(cursor->start_), graph_);
+            for (OutEdgeIterator oe = oer.first; oe != oer.second; ++ oe){
+                GraphVertex target = boost::target(*oe, graph_);
+                GroupPtr target_gr = GET(target);
+                // Each edge from condition must not leave the range [start, end].
+                if (
+                  (*start->start_)->_address > (*target_gr->start_)->_address
+                  || (*target_gr->start_)->_address > (*end->start_)->_address
+                ){
+                    return false;
+                }
+            }
+        }
+        // If previous group ends an else, that else must start inside the range.
+        for (
+          ElseEndIterator it = cursor->_prev->_endElse.begin();
+          it != cursor->_prev->_endElse.end();
+          ++ it
+        ){
+            if ((*(*it)->start_)->_address < (*start->start_)->_address) return false;
+        }
+        // Unless group is a simple unconditional jump...
+        if ((*cursor->start_)->IsUncondJump()) continue;
+        // ...validate ingoing edges
+        InEdgeRange ier = boost::in_edges(Find(cursor->start_), graph_);
+        for (InEdgeIterator ie = ier.first; ie != ier.second; ++ie){
+            GraphVertex source = boost::source(*ie, graph_);
+            GroupPtr source_gr = GET(source);
+            // Edges going to conditions...
+            if (
+              source_gr->_type == kIfCondGroupType
+              || source_gr->_type == kWhileCondGroupType
+              || source_gr->_type == kDoWhileCondGroupType
+            ){
+                // ...must not come from outside the range [start, end]...
+                if (
+                  (*start->start_)->_address > (*source_gr->start_)->_address
+                  || (*source_gr->start_)->_address > (*end->start_)->_address
+                ){
+                    // ...unless source is simple unconditional jump...
+                    if ((*source_gr->start_)->IsUncondJump()) continue;
+                    // ...or the edge is from the if condition associated with this else.
+                    if (if_group == source_gr) continue;
+                    return false;
+                }
+            }
+        }
+    }
+    return true;
+}

+ 0 - 534
V-Gears-Installer/src/decompiler/control_flow.cpp

@@ -1,534 +0,0 @@
-/* ScummVM Tools
- *
- * ScummVM Tools is the legal property of its developers, whose
- * names are too numerous to list here. Please refer to the
- * COPYRIGHT file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include "decompiler/control_flow.h"
-#include "decompiler/stack.h"
-
-#include <algorithm>
-#include <iostream>
-#include <set>
-
-#include <boost/format.hpp>
-
-#define PUT(vertex, group) boost::put(boost::vertex_name, _g, vertex, group);
-#define PUT_EDGE(edge, isJump) boost::put(boost::edge_attribute, _g, edge, isJump);
-#define PUT_ID(vertex, id) boost::put(boost::vertex_index, _g, vertex, id);
-#define GET(vertex) (boost::get(boost::vertex_name, _g, vertex))
-#define GET_EDGE(edge) (boost::get(boost::edge_attribute, _g, edge))
-
-ControlFlow::ControlFlow(InstVec& insts, Engine& engine)
-  : mInsts(insts), 
-    mEngine(engine)
-{
-
-	// Automatically add a function if we're not supposed to look for more functions and no functions are defined
-	// This avoids a special case for when no real functions exist in the script
-    if (mEngine._functions.empty())
-    {
-        mEngine._functions[(*insts.begin())->_address] = Function((*insts.begin())->_address, (insts.back())->_address);
-    }
-
-	GroupPtr prev = NULL;
-	int id = 0;
-	// Create vertices
-	for (InstIterator it = insts.begin(); it != insts.end(); ++it) {
-		GraphVertex cur = boost::add_vertex(_g);
-		_addrMap[(*it)->_address] = cur;
-		PUT(cur, new Group(cur, it, it, prev));
-		PUT_ID(cur, id);
-		id++;
-
-		// Add reference to vertex if function starts here
-		if (mEngine._functions.find((*it)->_address) != mEngine._functions.end())
-			mEngine._functions[(*it)->_address]._v = cur;
-
-		prev = GET(cur);
-	}
-
-	// Add regular edges
-	FuncMap::iterator fn;
-    GraphVertex last = {};
-	bool addEdge = false;
-	prev = NULL;
-	for (InstIterator it = insts.begin(); it != insts.end(); ++it) {
-		if (mEngine._functions.find((*it)->_address) != mEngine._functions.end()) {
-			addEdge = false;
-		}
-
-		GraphVertex cur = find(it);
-		if (addEdge) {
-			GraphEdge e = boost::add_edge(last, cur, _g).first;
-			PUT_EDGE(e, false);
-		}
-
-		last = cur;
-		addEdge = !((*it)->IsUncondJump() || (*it)->isReturn());
-		prev = GET(cur);
-
-	}
-
-	// Add jump edges
-	for (InstIterator it = insts.begin(); it != insts.end(); ++it) {
-		if ((*it)->isJump()) {
-			GraphEdge e = boost::add_edge(find(it), find((*it)->GetDestAddress()), _g).first;
-			PUT_EDGE(e, true);
-		}
-	}
-}
-
-GraphVertex ControlFlow::find(const InstPtr inst) {
-	return _addrMap[inst->_address];
-}
-
-GraphVertex ControlFlow::find(ConstInstIterator it) {
-	return _addrMap[(*it)->_address];
-}
-
-GraphVertex ControlFlow::find(uint32 address) {
-	std::map<uint32, GraphVertex>::iterator it = _addrMap.find(address);
-	if (it == _addrMap.end())
-		std::cerr << "Request for instruction at unknown address " << boost::format("0x%08x") % address << std::endl;
-	return it->second;
-}
-
-void ControlFlow::merge(GraphVertex g1, GraphVertex g2) {
-	// Update property
-	GroupPtr gr1 = GET(g1);
-	GroupPtr gr2 = GET(g2);
-	gr1->end_ = gr2->end_;
-	PUT(g1, gr1);
-
-	// Update address map
-	ConstInstIterator it = gr2->start_;
-	do {
-		_addrMap[(*it)->_address] = g1;
-		++it;
-	} while (gr2->start_ != gr2->end_ && it != gr2->end_);
-
-	// Add outgoing edges from g2
-	OutEdgeRange r = boost::out_edges(g2, _g);
-	for (OutEdgeIterator e = r.first; e != r.second; ++e) {
-		GraphEdge newE = boost::add_edge(g1, boost::target(*e, _g), _g).first;
-		PUT_EDGE(newE, GET_EDGE(*e));
-	}
-
-	// Update _next pointer
-	gr1->_next = gr2->_next;
-	if (gr2->_next != NULL)
-		gr2->_next->_prev = gr2->_prev;
-
-	// Remove edges to/from g2
-	boost::clear_vertex(g2, _g);
-	// Remove vertex
-	boost::remove_vertex(g2, _g);
-}
-
-typedef std::pair<GraphVertex, int> LevelEntry;
-
-void ControlFlow::setStackLevel(GraphVertex g, int level) {
-	Stack<LevelEntry> levelStack;
-	std::set<GraphVertex> seen;
-	levelStack.push(LevelEntry(g, level));
-	seen.insert(g);
-	while (!levelStack.empty()) {
-		LevelEntry e = levelStack.pop();
-		GroupPtr gr = GET(e.first);
-		if (gr->_stackLevel != -1) {
-			if (gr->_stackLevel != e.second)
-				std::cerr << boost::format("WARNING: Inconsistency in expected stack level for instruction at address 0x%08x (current: %d, requested: %d)\n") % (*gr->start_)->_address % gr->_stackLevel % e.second;
-			continue;
-		}
-		gr->_stackLevel = e.second;
-
-		OutEdgeRange r = boost::out_edges(e.first, _g);
-		for (OutEdgeIterator oe = r.first; oe != r.second; ++oe) {
-			GraphVertex target = boost::target(*oe, _g);
-			if (seen.find(target) == seen.end()) {
-				levelStack.push(LevelEntry(target, e.second + (*gr->start_)->_stackChange));
-				seen.insert(target);
-			}
-		}
-	}
-}
-
-void ControlFlow::createGroups() 
-{
-    if (!mEngine._functions.empty() && GET(mEngine._functions.begin()->second._v)->_stackLevel != -1)
-    {
-        return;
-    }
-
-	for (FuncMap::iterator fn = mEngine._functions.begin(); fn != mEngine._functions.end(); ++fn)
-		setStackLevel(fn->second._v, 0);
-	ConstInstIterator curInst, nextInst;
-	nextInst = mInsts.begin();
-	nextInst++;
-	int stackLevel = 0;
-	int expectedStackLevel = 0;
-	for (curInst = mInsts.begin(); nextInst != mInsts.end(); ++curInst, ++nextInst) {
-		GraphVertex cur = find(curInst);
-		GraphVertex next = find(nextInst);
-
-		GroupPtr grCur = GET(cur);
-		GroupPtr grNext = GET(next);
-
-		// Don't process unreachable code
-		if (grCur->_stackLevel < 0) {
-			stackLevel = grNext->_stackLevel;
-			continue;
-		}
-
-		expectedStackLevel = grCur->_stackLevel;
-		// If expected stack level decreases in next vertex, then use next vertex level as expected level
-		if (expectedStackLevel > grNext->_stackLevel && grNext->_stackLevel >= 0) {
-			expectedStackLevel = grNext->_stackLevel;
-			// Also set the stack level of the current group to remember that we expect it to be lower
-			grCur->_stackLevel = expectedStackLevel;
-		}
-
-		stackLevel += (*curInst)->_stackChange;
-
-		// For stack operations, the new stack level becomes the expected stack level starting from the next group
-		if ((*curInst)->isStackOp()) {
-			expectedStackLevel = stackLevel;
-			grNext->_stackLevel = stackLevel;
-		}
-
-		// Group ends after a jump
-		if ((*curInst)->isJump()) {
-			stackLevel = grNext->_stackLevel;
-			continue;
-		}
-
-		// Group ends with a return
-		if ((*curInst)->isReturn()) {
-			stackLevel = grNext->_stackLevel;
-			continue;
-		}
-
-		// Group ends before target of a jump
-		if (in_degree(next, _g) != 1) {
-			stackLevel = grNext->_stackLevel;
-			continue;
-		}
-
-		// This part is only relevant if we use the stack level.
-		if (!mEngine.UsePureGrouping()) {
-			// If group has no instructions with stack effect >= 0, don't merge on balanced stack
-			bool forceMerge = true;
-			ConstInstIterator it = grCur->start_;
-			do {
-				if ((*it)->_stackChange >= 0)
-					forceMerge = false;
-				++it;
-			} while (grCur->start_ != grCur->end_ && it != grCur->end_);
-
-			// Group ends when stack is balanced, unless just before conditional jump
-			if (stackLevel == expectedStackLevel && !forceMerge && !(*nextInst)->isCondJump()) {
-				continue;
-			}
-		}
-
-		// All checks passed, merge groups
-		merge(cur, next);
-	}
-
-	// FIXME: The short-circuit detection is disabled because short-circuited groups require some special handling
-	// in the code generation. It's not entirely clear how to handle it properly, though: you need to deduce which
-	// effect is created by the conditional jumps in the middle of a block, which seems to get fairly complex when
-	// you have multiple groups that are merged by the short-circuit detection.
-	//detectShortCircuit();
-}
-
-void ControlFlow::detectShortCircuit() {
-	ConstInstIterator lastInst = mInsts.end();
-	--lastInst;
-	GraphVertex cur = find(lastInst);
-	GroupPtr gr = GET(cur);
-	while (gr->_prev != NULL) {
-		bool doMerge = false;
-		cur = find(gr->start_);
-		GraphVertex prev = find(gr->_prev->start_);
-		// Block is candidate for short-circuit merging if it and the preceding block both end with conditional jumps
-		if (out_degree(cur, _g) == 2 && out_degree(prev, _g) == 2) {
-			doMerge = true;
-			OutEdgeRange rCur = boost::out_edges(cur, _g);
-			std::vector<GraphVertex> succs;
-
-			// Find possible target vertices
-			for (OutEdgeIterator it = rCur.first; it != rCur.second; ++it) {
-				succs.push_back(boost::target(*it, _g));
-			}
-
-			// Check if vertex would add new targets - if yes, don't merge
-			OutEdgeRange rPrev = boost::out_edges(prev, _g);
-			for (OutEdgeIterator it = rPrev.first; it != rPrev.second; ++it) {
-				GraphVertex target = boost::target(*it, _g);
-				doMerge &= (std::find(succs.begin(), succs.end(), target) != succs.end() || target == cur);
-			}
-
-			if (doMerge) {
-				gr = gr->_prev;
-				merge(prev, cur);
-				continue;
-			}
-		}
-		gr = gr->_prev;
-	}
-}
-
-const Graph &ControlFlow::analyze() {
-	detectDoWhile();
-	detectWhile();
-	detectBreak();
-	detectContinue();
-	detectIf();
-	detectElse();
-	return _g;
-}
-
-void ControlFlow::detectWhile() {
-	VertexRange vr = boost::vertices(_g);
-	for (VertexIterator v = vr.first; v != vr.second; ++v) {
-		GroupPtr gr = GET(*v);
-		// Undetermined block that ends with conditional jump
-		if (out_degree(*v, _g) == 2 && gr->_type == kNormalGroupType) {
-			InEdgeRange ier = boost::in_edges(*v, _g);
-			bool isWhile = false;
-			for (InEdgeIterator e = ier.first; e != ier.second; ++e) {
-				GroupPtr sourceGr = GET(boost::source(*e, _g));
-				// Block has ingoing edge from block later in the code that isn't a do-while condition
-				if ((*sourceGr->start_)->_address > (*gr->start_)->_address && sourceGr->_type != kDoWhileCondGroupType)
-					isWhile = true;
-			}
-			if (isWhile)
-				gr->_type = kWhileCondGroupType;
-		}
-	}
-}
-
-void ControlFlow::detectDoWhile() {
-	VertexRange vr = boost::vertices(_g);
-	for (VertexIterator v = vr.first; v != vr.second; ++v) {
-		GroupPtr gr = GET(*v);
-		// Undetermined block that ends with conditional jump...
-		if (out_degree(*v, _g) == 2 && gr->_type == kNormalGroupType) {
-			OutEdgeRange oer = boost::out_edges(*v, _g);
-			for (OutEdgeIterator e = oer.first; e != oer.second; ++e) {
-				GroupPtr targetGr = GET(boost::target(*e, _g));
-				// ...to earlier in code
-				if ((*targetGr->start_)->_address < (*gr->start_)->_address)
-					gr->_type = kDoWhileCondGroupType;
-			}
-		}
-	}
-}
-
-void ControlFlow::detectBreak() {
-	VertexRange vr = boost::vertices(_g);
-	for (VertexIterator v = vr.first; v != vr.second; ++v) {
-		GroupPtr gr = GET(*v);
-		// Undetermined block with unconditional jump...
-		if (gr->_type == kNormalGroupType && ((*gr->end_)->IsUncondJump()) && out_degree(*v, _g) == 1) {
-			OutEdgeIterator oe = boost::out_edges(*v, _g).first;
-			GraphVertex target = boost::target(*oe, _g);
-			GroupPtr targetGr = GET(target);
-			// ...to somewhere later in the code...
-			if ((*gr->start_)->_address >= (*targetGr->start_)->_address)
-				continue;
-			InEdgeRange ier = boost::in_edges(target, _g);
-			for (InEdgeIterator ie = ier.first; ie != ier.second; ++ie) {
-				GroupPtr sourceGr = GET(boost::source(*ie, _g));
-				// ...to block immediately after a do-while condition, or to jump target of a while condition
-				if ((targetGr->_prev == sourceGr && sourceGr->_type == kDoWhileCondGroupType) || sourceGr->_type == kWhileCondGroupType) {
-					if (validateBreakOrContinue(gr, sourceGr))
-						gr->_type = kBreakGroupType;
-				}
-			}
-		}
-	}
-}
-
-void ControlFlow::detectContinue() {
-	VertexRange vr = boost::vertices(_g);
-	for (VertexIterator v = vr.first; v != vr.second; ++v) {
-		GroupPtr gr = GET(*v);
-		// Undetermined block with unconditional jump...
-		if (gr->_type == kNormalGroupType && ((*gr->end_)->IsUncondJump()) && out_degree(*v, _g) == 1) {
-			OutEdgeIterator oe = boost::out_edges(*v, _g).first;
-			GraphVertex target = boost::target(*oe, _g);
-			GroupPtr targetGr = GET(target);
-			// ...to a while or do-while condition...
-			if (targetGr->_type == kWhileCondGroupType || targetGr->_type == kDoWhileCondGroupType) {
-				bool isContinue = true;
-				// ...unless...
-				OutEdgeRange toer = boost::out_edges(target, _g);
-				bool afterJumpTargets = true;
-				for (OutEdgeIterator toe = toer.first; toe != toer.second; ++toe) {
-					// ...it is targeting a while condition which jumps to the next sequential group
-					if (targetGr->_type == kWhileCondGroupType && GET(boost::target(*toe, _g)) == gr->_next)
-						isContinue = false;
-					// ...or the instruction is placed after all jump targets from condition
-					if ((*GET(boost::target(*toe, _g))->start_)->_address > (*gr->start_)->_address)
-						afterJumpTargets = false;
-				}
-				if (afterJumpTargets)
-					isContinue = false;
-
-				if (isContinue && validateBreakOrContinue(gr, targetGr))
-					gr->_type = kContinueGroupType;
-			}
-		}
-	}
-}
-
-bool ControlFlow::validateBreakOrContinue(GroupPtr gr, GroupPtr condGr) {
-	GroupPtr from, to, cursor;
-
-	if (condGr->_type == kDoWhileCondGroupType) {
-		to = condGr;
-		from = gr;
-	}	else {
-		to = gr;
-		from = condGr->_next;
-	}
-
-	GroupType ogt = (condGr->_type == kDoWhileCondGroupType ? kWhileCondGroupType : kDoWhileCondGroupType);
-	// Verify that destination deals with innermost while/do-while
-	for (cursor = from; cursor->_next != NULL && cursor != to; cursor = cursor->_next) {
-		if (cursor->_type == condGr->_type) {
-			OutEdgeRange oerValidate = boost::out_edges(find(cursor->start_), _g);
-			for (OutEdgeIterator oeValidate = oerValidate.first; oeValidate != oerValidate.second; ++oeValidate) {
-				GraphVertex vValidate = boost::target(*oeValidate, _g);
-				GroupPtr gValidate = GET(vValidate);
-				// For all other loops of same type found in range, all targets must fall within that range
-				if ((*gValidate->start_)->_address < (*from->start_)->_address || (*gValidate->start_)->_address > (*to->start_)->_address )
-					return false;
-
-				InEdgeRange ierValidate = boost::in_edges(vValidate, _g);
-				for (InEdgeIterator ieValidate = ierValidate.first; ieValidate != ierValidate.second; ++ieValidate) {
-					GroupPtr igValidate = GET(boost::source(*ieValidate, _g));
-					// All loops of other type going into range must be placed within range
-					if (igValidate->_type == ogt && ((*igValidate->start_)->_address < (*from->start_)->_address || (*igValidate->start_)->_address > (*to->start_)->_address ))
-					return false;
-				}
-			}
-		}
-	}
-	return true;
-}
-
-void ControlFlow::detectIf() {
-	VertexRange vr = boost::vertices(_g);
-	for (VertexIterator v = vr.first; v != vr.second; ++v) {
-		GroupPtr gr = GET(*v);
-		// if: Undetermined block with conditional jump
-		if (gr->_type == kNormalGroupType && ((*gr->end_)->isCondJump())) {
-			gr->_type = kIfCondGroupType;
-		}
-	}
-}
-
-void ControlFlow::detectElse() {
-	VertexRange vr = boost::vertices(_g);
-	for (VertexIterator v = vr.first; v != vr.second; ++v) {
-		GroupPtr gr = GET(*v);
-		if (gr->_type == kIfCondGroupType) {
-			OutEdgeRange oer = boost::out_edges(*v, _g);
-			GraphVertex target;
-			uint32 maxAddress = 0;
-			GroupPtr targetGr;
-			// Find jump target
-			for (OutEdgeIterator oe = oer.first; oe != oer.second; ++oe) {
-				targetGr = GET(boost::target(*oe, _g));
-				if ((*targetGr->start_)->_address > maxAddress) {
-					target = boost::target(*oe, _g);
-					maxAddress = (*targetGr->start_)->_address;
-				}
-			}
-			targetGr = GET(target);
-			// else: Jump target of if immediately preceded by an unconditional jump...
-			if (!(*targetGr->_prev->end_)->IsUncondJump())
-				continue;
-			// ...which is not a break or a continue...
-			if (targetGr->_prev->_type == kContinueGroupType || targetGr->_prev->_type == kBreakGroupType)
-				continue;
-			// ...to later in the code
-			OutEdgeIterator toe = boost::out_edges(find((*targetGr->_prev->start_)->_address), _g).first;
-			GroupPtr targetTargetGr = GET(boost::target(*toe, _g));
-			if ((*targetTargetGr->start_)->_address > (*targetGr->end_)->_address) {
-				if (validateElseBlock(gr, targetGr, targetTargetGr)) {
-					targetGr->_startElse = true;
-					targetTargetGr->_prev->_endElse.push_back(targetGr.get());
-				}
-			}
-		}
-	}
-}
-
-bool ControlFlow::validateElseBlock(GroupPtr ifGroup, GroupPtr start, GroupPtr end) {
-	for (GroupPtr cursor = start; cursor != end; cursor = cursor->_next) {
-		if (cursor->_type == kIfCondGroupType || cursor->_type == kWhileCondGroupType || cursor->_type == kDoWhileCondGroupType) {
-			// Validate outgoing edges of conditions
-			OutEdgeRange oer = boost::out_edges(find(cursor->start_), _g);
-			for (OutEdgeIterator oe = oer.first; oe != oer.second; ++oe) {
-				GraphVertex target = boost::target(*oe, _g);
-				GroupPtr targetGr = GET(target);
-				// Each edge from condition must not leave the range [start, end]
-				if ((*start->start_)->_address > (*targetGr->start_)->_address || (*targetGr->start_)->_address > (*end->start_)->_address)
-					return false;
-			}
-		}
-
-		// If previous group ends an else, that else must start inside the range
-		for (ElseEndIterator it = cursor->_prev->_endElse.begin(); it != cursor->_prev->_endElse.end(); ++it)
-		{
-			if ((*(*it)->start_)->_address < (*start->start_)->_address)
-				return false;
-		}
-
-		// Unless group is a simple unconditional jump...
-		if ((*cursor->start_)->IsUncondJump())
-			continue;
-
-		// ...validate ingoing edges
-		InEdgeRange ier = boost::in_edges(find(cursor->start_), _g);
-		for (InEdgeIterator ie = ier.first; ie != ier.second; ++ie) {
-			GraphVertex source = boost::source(*ie, _g);
-			GroupPtr sourceGr = GET(source);
-
-			// Edges going to conditions...
-			if (sourceGr->_type == kIfCondGroupType || sourceGr->_type == kWhileCondGroupType || sourceGr->_type == kDoWhileCondGroupType) {
-				// ...must not come from outside the range [start, end]...
-				if ((*start->start_)->_address > (*sourceGr->start_)->_address || (*sourceGr->start_)->_address > (*end->start_)->_address) {
-					// ...unless source is simple unconditional jump...
-					if ((*sourceGr->start_)->IsUncondJump())
-						continue;
-					// ...or the edge is from the if condition associated with this else
-					if (ifGroup == sourceGr)
-						continue;
-					return false;
-				}
-			}
-		}
-	}
-	return true;
-}

+ 1 - 2
V-Gears-Installer/src/decompiler/decompiler.cpp

@@ -25,13 +25,12 @@
 #include "decompiler_engine.h"
 #include "instruction.h"
 
-#include "control_flow.h"
-
 #include <fstream>
 #include <iostream>
 #include <map>
 #include <string>
 #include <vector>
+#include "../../include/decompiler/ControlFlow.h"
 
 #ifdef _MSC_VER
 #pragma warning (push)

+ 1 - 1
V-Gears-Installer/src/decompiler/field/FieldDisassembler.cpp

@@ -14,10 +14,10 @@
  */
 
 #include <vector>
-#include "decompiler/decompiler_engine.h"
 #include <boost/format.hpp>
 #include <boost/algorithm/string/split.hpp>
 #include <boost/algorithm/string.hpp>
+#include "decompiler/decompiler_engine.h"
 #include "decompiler/field/FieldCodeGenerator.h"
 #include "decompiler/field/FieldDisassembler.h"
 #include "decompiler/field/FieldEngine.h"

+ 2 - 2
V-Gears-Installer/src/decompiler/sudm.cpp

@@ -15,10 +15,10 @@
 
 #include "decompiler/sudm.h"
 
+#include "../../include/decompiler/ControlFlow.h"
 #include "../../include/decompiler/field/FieldCodeGenerator.h"
 #include "../../include/decompiler/field/FieldDisassembler.h"
 #include "../../include/decompiler/field/FieldEngine.h"
-#include "decompiler/control_flow.h"
 
 namespace SUDM{
     namespace FF7{
@@ -50,7 +50,7 @@ namespace SUDM{
                 disassembler->disassemble();
                 // Create control flow group.
                 auto control_flow = std::make_unique<ControlFlow>(insts, engine);
-                control_flow->createGroups();
+                control_flow->CreateGroups();
                 // Decompile/analyze
                 //Graph graph = controlFlow->analyze();
                 //engine.PostCFG(insts, graph);

+ 1 - 1
V-Gears-Installer/src/ff7DataInstaller.cpp

@@ -29,7 +29,7 @@
 #include <OgreHardwarePixelBuffer.h>
 #include <OgreResourceGroupManager.h>
 #include <OgreLog.h>
-#include "../include/ff7DataInstaller.h"
+#include "ff7DataInstaller.h"
 #include "VGearsGameState.h"
 #include "data/VGearsAFileManager.h"
 #include "data/VGearsBackgroundFileManager.h"