mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 11:26:18 -04:00
87be9ebd14
Fixes #2993
206 lines
6.7 KiB
C++
206 lines
6.7 KiB
C++
/*!
|
|
* @file GenericElementMatcher.h
|
|
*
|
|
* The Matcher is supposed to match up forms to templates, and extract the variables actually used.
|
|
*/
|
|
|
|
#pragma once
|
|
#include "Env.h"
|
|
#include "Form.h"
|
|
|
|
namespace decompiler {
|
|
class DerefTokenMatcher;
|
|
class GenericOpMatcher;
|
|
class LetEntryMatcher;
|
|
|
|
struct MatchResult {
|
|
bool matched = false;
|
|
struct Maps {
|
|
std::vector<std::optional<RegisterAccess>> regs;
|
|
std::unordered_map<int, std::string> strings;
|
|
std::unordered_map<int, Form*> forms;
|
|
std::unordered_map<int, s64> label;
|
|
std::unordered_map<int, s64> ints;
|
|
} maps;
|
|
|
|
Form* int_or_form_to_form(FormPool& pool, int key_idx) {
|
|
if (maps.forms.find(key_idx) != maps.forms.end()) {
|
|
return maps.forms.at(key_idx);
|
|
} else {
|
|
return pool.form<SimpleAtomElement>(SimpleAtom::make_int_constant(maps.ints.at(key_idx)));
|
|
}
|
|
}
|
|
};
|
|
|
|
class Matcher {
|
|
public:
|
|
static Matcher any_reg(int match_id = -1);
|
|
static Matcher same_var(int match_id);
|
|
static Matcher var_name(const std::string& name);
|
|
static Matcher any_label(int match_id = -1);
|
|
static Matcher reg(Register reg);
|
|
static inline Matcher s6() { return Matcher::reg(Register(Reg::GPR, Reg::S6)); }
|
|
static Matcher op(const GenericOpMatcher& op, const std::vector<Matcher>& args);
|
|
static Matcher func(const Matcher& match, const std::vector<Matcher>& args);
|
|
static Matcher func(const std::string& name, const std::vector<Matcher>& args);
|
|
static Matcher op_fixed(FixedOperatorKind op, const std::vector<Matcher>& args);
|
|
static Matcher op_with_rest(const GenericOpMatcher& op, const std::vector<Matcher>& args);
|
|
static Matcher func_with_rest(const Matcher& match, const std::vector<Matcher>& args);
|
|
static Matcher func_with_rest(const std::string& name, const std::vector<Matcher>& args);
|
|
static Matcher set(const Matcher& dst, const Matcher& src); // form-form
|
|
static Matcher set_var(const Matcher& src, int dst_match_id); // var-form
|
|
static Matcher match_or(const std::vector<Matcher>& args);
|
|
static Matcher cast(const std::string& type, Matcher value);
|
|
static Matcher cast_to_any(int type_out, Matcher value);
|
|
static Matcher any(int match_id = -1);
|
|
static Matcher integer(std::optional<int> value);
|
|
static Matcher any_integer(int match_id = -1);
|
|
static Matcher single(std::optional<float> value);
|
|
static Matcher any_reg_cast_to_int_or_uint(int match_id = -1);
|
|
static Matcher any_quoted_symbol(int match_id = -1);
|
|
static Matcher any_symbol(int match_id = -1);
|
|
static Matcher quoted_symbol(const std::string& name);
|
|
static Matcher symbol(const std::string& name);
|
|
static Matcher deref(const Matcher& root,
|
|
bool is_addr_of,
|
|
const std::vector<DerefTokenMatcher>& tokens);
|
|
static Matcher if_with_else(const Matcher& condition,
|
|
const Matcher& true_case,
|
|
const Matcher& false_case);
|
|
static Matcher if_no_else(const Matcher& condition, const Matcher& true_case);
|
|
static Matcher while_loop(const Matcher& condition, const Matcher& body);
|
|
static Matcher any_constant_token(int match_id = -1);
|
|
static Matcher constant_token(const std::string& name);
|
|
static Matcher or_expression(const std::vector<Matcher>& elts);
|
|
static Matcher begin(const std::vector<Matcher>& elts);
|
|
static Matcher let(bool is_star,
|
|
const std::vector<LetEntryMatcher>& entries,
|
|
const std::vector<Matcher>& elts);
|
|
|
|
enum class Kind {
|
|
ANY_REG, // matching any register
|
|
GENERIC_OP, // matching
|
|
GENERIC_OP_WITH_REST,
|
|
OR,
|
|
CAST,
|
|
CAST_TO_ANY,
|
|
ANY,
|
|
INT,
|
|
ANY_INT,
|
|
FLOAT,
|
|
ANY_QUOTED_SYMBOL,
|
|
ANY_SYMBOL,
|
|
DEREF_OP,
|
|
SET,
|
|
SET_VAR,
|
|
ANY_LABEL,
|
|
SYMBOL,
|
|
IF_WITH_ELSE,
|
|
IF_NO_ELSE,
|
|
WHILE_LOOP,
|
|
ANY_CONSTANT_TOKEN,
|
|
CONSTANT_TOKEN,
|
|
SC_OR,
|
|
BEGIN,
|
|
REG, // a specific register. like s6.
|
|
QUOTED_SYMBOL,
|
|
SAME_VAR,
|
|
LET,
|
|
VAR_NAME,
|
|
INVALID
|
|
};
|
|
|
|
bool do_match(Form* input, MatchResult::Maps* maps_out, const Env* const env) const;
|
|
|
|
private:
|
|
std::vector<Matcher> m_sub_matchers;
|
|
std::vector<DerefTokenMatcher> m_token_matchers;
|
|
std::vector<LetEntryMatcher> m_entry_matchers;
|
|
std::shared_ptr<GenericOpMatcher> m_gen_op_matcher;
|
|
bool m_deref_is_addr_of = false;
|
|
bool m_let_is_star = false;
|
|
Kind m_kind = Kind::INVALID;
|
|
union {
|
|
int m_out_id = -1;
|
|
int m_reg_out_id;
|
|
int m_string_out_id;
|
|
int m_form_match;
|
|
int m_label_out_id;
|
|
int m_int_out_id;
|
|
};
|
|
std::optional<int> m_int_match;
|
|
std::optional<float> m_float_match;
|
|
std::optional<Register> m_reg;
|
|
std::string m_str;
|
|
};
|
|
|
|
MatchResult match(const Matcher& spec, Form* input, const Env* const env = nullptr);
|
|
MatchResult match(const Matcher& spec, FormElement* input, const Env* const env = nullptr);
|
|
|
|
class DerefTokenMatcher {
|
|
public:
|
|
static DerefTokenMatcher string(const std::string& str);
|
|
static DerefTokenMatcher integer(int value);
|
|
static DerefTokenMatcher any_string(int match_id = -1);
|
|
static DerefTokenMatcher any_integer(int match_id = -1);
|
|
static DerefTokenMatcher any_expr(int match_id = -1);
|
|
static DerefTokenMatcher any_expr_or_int(int match_id = -1);
|
|
|
|
enum class Kind {
|
|
STRING,
|
|
ANY_STRING,
|
|
CONSTANT_INTEGER,
|
|
ANY_INTEGER,
|
|
ANY_EXPR,
|
|
ANY_EXPR_OR_INT,
|
|
INVALID
|
|
};
|
|
|
|
bool do_match(DerefToken& input, MatchResult::Maps* maps_out) const;
|
|
|
|
private:
|
|
Kind m_kind = Kind::INVALID;
|
|
std::string m_str;
|
|
int m_int = -1;
|
|
int m_str_out_id = -1;
|
|
};
|
|
|
|
class GenericOpMatcher {
|
|
public:
|
|
static GenericOpMatcher fixed(FixedOperatorKind kind);
|
|
static GenericOpMatcher func(const Matcher& func_matcher);
|
|
static GenericOpMatcher condition(IR2_Condition::Kind condition);
|
|
static GenericOpMatcher or_match(const std::vector<GenericOpMatcher>& matchers);
|
|
|
|
enum class Kind { FIXED, FUNC, CONDITION, OR, INVALID };
|
|
|
|
bool do_match(GenericOperator& input, MatchResult::Maps* maps_out, const Env* const env) const;
|
|
|
|
private:
|
|
Kind m_kind = Kind::INVALID;
|
|
FixedOperatorKind m_fixed_kind = FixedOperatorKind::INVALID;
|
|
IR2_Condition::Kind m_condition_kind = IR2_Condition::Kind::INVALID;
|
|
std::vector<GenericOpMatcher> m_sub_matchers;
|
|
Matcher m_func_matcher;
|
|
};
|
|
|
|
class LetEntryMatcher {
|
|
public:
|
|
static LetEntryMatcher name(std::optional<Matcher> src_matcher, const std::string& name);
|
|
static LetEntryMatcher any(std::optional<Matcher> src_matcher, int match_id = -1);
|
|
|
|
enum class Kind { ANY, NAME, INVALID };
|
|
|
|
bool do_match(const LetElement::Entry& input,
|
|
MatchResult::Maps* maps_out,
|
|
const Env* const env) const;
|
|
|
|
private:
|
|
Kind m_kind = Kind::INVALID;
|
|
int m_reg_out_id = -1;
|
|
std::optional<Matcher> m_src_matcher;
|
|
std::string m_reg_name;
|
|
};
|
|
|
|
} // namespace decompiler
|