Added math evaluator / calculator to tools window
This commit is contained in:
parent
0f6e276113
commit
c90ef343c1
@ -27,9 +27,11 @@ SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
|
||||
add_executable(ImHex
|
||||
source/main.cpp
|
||||
source/window.cpp
|
||||
source/utils.cpp
|
||||
source/crypto.cpp
|
||||
source/patches.cpp
|
||||
|
||||
source/helpers/utils.cpp
|
||||
source/helpers/crypto.cpp
|
||||
source/helpers/patches.cpp
|
||||
source/helpers/math_evaluator.cpp
|
||||
|
||||
source/lang/preprocessor.cpp
|
||||
source/lang/lexer.cpp
|
||||
|
88
include/helpers/math_evaluator.hpp
Normal file
88
include/helpers/math_evaluator.hpp
Normal file
@ -0,0 +1,88 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
|
||||
namespace hex {
|
||||
|
||||
enum class TokenType {
|
||||
Number,
|
||||
Variable,
|
||||
Function,
|
||||
Operator,
|
||||
Bracket
|
||||
};
|
||||
|
||||
enum class Operator : u16 {
|
||||
Invalid = 0x000,
|
||||
Assign = 0x010,
|
||||
Or = 0x020,
|
||||
Xor = 0x030,
|
||||
And = 0x040,
|
||||
BitwiseOr = 0x050,
|
||||
BitwiseXor = 0x060,
|
||||
BitwiseAnd = 0x070,
|
||||
Equals = 0x080,
|
||||
NotEquals = 0x081,
|
||||
GreaterThan = 0x090,
|
||||
LessThan = 0x091,
|
||||
GreaterThanOrEquals = 0x092,
|
||||
LessThanOrEquals = 0x093,
|
||||
ShiftLeft = 0x0A0,
|
||||
ShiftRight = 0x0A1,
|
||||
Addition = 0x0B0,
|
||||
Subtraction = 0x0B1,
|
||||
Multiplication = 0x0C0,
|
||||
Division = 0x0C1,
|
||||
Modulus = 0x0C2,
|
||||
Exponentiation = 0x1D0,
|
||||
Combine = 0x0E0,
|
||||
BitwiseNot = 0x0F0,
|
||||
Not = 0x0F1
|
||||
};
|
||||
|
||||
enum class BracketType : std::uint8_t {
|
||||
Left,
|
||||
Right
|
||||
};
|
||||
|
||||
struct Token {
|
||||
TokenType type;
|
||||
|
||||
long double number;
|
||||
Operator op;
|
||||
BracketType bracketType;
|
||||
std::string name;
|
||||
std::vector<long double> arguments;
|
||||
};
|
||||
|
||||
class MathEvaluator {
|
||||
public:
|
||||
MathEvaluator() = default;
|
||||
|
||||
std::optional<long double> evaluate(std::string input);
|
||||
|
||||
void registerStandardVariables();
|
||||
void registerStandardFunctions();
|
||||
|
||||
void setVariable(std::string name, long double value);
|
||||
void setFunction(std::string name, std::function<std::optional<long double>(std::vector<long double>)> function, size_t minNumArgs, size_t maxNumArgs);
|
||||
|
||||
const std::unordered_map<std::string, long double>& getVariables() { return this->m_variables; }
|
||||
|
||||
private:
|
||||
std::queue<Token> parseInput(const char *input);
|
||||
std::queue<Token> toPostfix(std::queue<Token> inputQueue);
|
||||
std::optional<long double> evaluate(std::queue<Token> postfixTokens);
|
||||
|
||||
std::unordered_map<std::string, long double> m_variables;
|
||||
std::unordered_map<std::string, std::function<std::optional<long double>(std::vector<long double>)>> m_functions;
|
||||
};
|
||||
|
||||
}
|
@ -7,7 +7,7 @@
|
||||
#include "imgui_memory_editor.h"
|
||||
|
||||
#include "providers/provider.hpp"
|
||||
#include "utils.hpp"
|
||||
#include "helpers/utils.hpp"
|
||||
|
||||
#include <random>
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
#include "imgui.h"
|
||||
|
||||
#include "event.hpp"
|
||||
#include "helpers/event.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
#include "utils.hpp"
|
||||
#include "helpers/utils.hpp"
|
||||
|
||||
namespace hex {
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils.hpp"
|
||||
#include "helpers/utils.hpp"
|
||||
#include "views/view.hpp"
|
||||
|
||||
#include "imgui_memory_editor.h"
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "imgui.h"
|
||||
#include "views/view.hpp"
|
||||
#include "helpers/math_evaluator.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
@ -33,10 +34,16 @@ namespace hex {
|
||||
|
||||
std::array<float, 4> m_pickedColor;
|
||||
|
||||
MathEvaluator m_mathEvaluator;
|
||||
std::vector<long double> m_mathHistory;
|
||||
std::string m_lastMathError;
|
||||
char *m_mathInput = nullptr;
|
||||
|
||||
void drawDemangler();
|
||||
void drawASCIITable();
|
||||
void drawRegexReplacer();
|
||||
void drawColorPicker();
|
||||
void drawMathEvaluator();
|
||||
};
|
||||
|
||||
}
|
@ -46,7 +46,7 @@
|
||||
|
||||
#include <stdio.h> // sprintf, scanf
|
||||
#include <stdint.h> // uint8_t, etc.
|
||||
#include "utils.hpp"
|
||||
#include "helpers/utils.hpp"
|
||||
|
||||
#include "views/view.hpp"
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include "crypto.hpp"
|
||||
#include "helpers/crypto.hpp"
|
||||
|
||||
#include "providers/provider.hpp"
|
||||
|
390
source/helpers/math_evaluator.cpp
Normal file
390
source/helpers/math_evaluator.cpp
Normal file
@ -0,0 +1,390 @@
|
||||
#include "helpers/math_evaluator.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <queue>
|
||||
#include <stack>
|
||||
#include <stdexcept>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <numbers>
|
||||
|
||||
namespace hex {
|
||||
|
||||
s16 comparePrecedence(const Operator& a, const Operator& b) {
|
||||
return (static_cast<s8>(a) & 0x0F0) - (static_cast<s8>(b) & 0x0F0);
|
||||
}
|
||||
|
||||
bool isLeftAssociative(const Operator op) {
|
||||
return (static_cast<u32>(op) & 0xF00) == 0;
|
||||
}
|
||||
|
||||
std::pair<Operator, size_t> toOperator(std::string input) {
|
||||
if (input.starts_with("##")) return { Operator::Combine, 2 };
|
||||
if (input.starts_with("==")) return { Operator::Equals, 2 };
|
||||
if (input.starts_with("!=")) return { Operator::NotEquals, 2 };
|
||||
if (input.starts_with(">=")) return { Operator::GreaterThanOrEquals, 2 };
|
||||
if (input.starts_with("<=")) return { Operator::LessThanOrEquals, 2 };
|
||||
if (input.starts_with(">>")) return { Operator::ShiftRight, 2 };
|
||||
if (input.starts_with("<<")) return { Operator::ShiftLeft, 2 };
|
||||
if (input.starts_with("||")) return { Operator::Or, 2 };
|
||||
if (input.starts_with("^^")) return { Operator::Xor, 2 };
|
||||
if (input.starts_with("&&")) return { Operator::And, 2 };
|
||||
if (input.starts_with("**")) return { Operator::Exponentiation, 2 };
|
||||
if (input.starts_with(">")) return { Operator::GreaterThan, 1 };
|
||||
if (input.starts_with("<")) return { Operator::LessThan, 1 };
|
||||
if (input.starts_with("!")) return { Operator::Not, 1 };
|
||||
if (input.starts_with("|")) return { Operator::BitwiseOr, 1 };
|
||||
if (input.starts_with("^")) return { Operator::BitwiseXor, 1 };
|
||||
if (input.starts_with("&")) return { Operator::BitwiseAnd, 1 };
|
||||
if (input.starts_with("~")) return { Operator::BitwiseNot, 1 };
|
||||
if (input.starts_with("+")) return { Operator::Addition, 1 };
|
||||
if (input.starts_with("-")) return { Operator::Subtraction, 1 };
|
||||
if (input.starts_with("*")) return { Operator::Multiplication, 1 };
|
||||
if (input.starts_with("/")) return { Operator::Division, 1 };
|
||||
if (input.starts_with("%")) return { Operator::Modulus, 1 };
|
||||
if (input.starts_with("=")) return { Operator::Assign, 1 };
|
||||
|
||||
return { Operator::Invalid, 0 };
|
||||
}
|
||||
|
||||
std::queue<Token> MathEvaluator::parseInput(const char *input) {
|
||||
std::queue<Token> inputQueue;
|
||||
|
||||
char *prevPos = const_cast<char*>(input);
|
||||
for (char *pos = prevPos; *pos != 0x00;) {
|
||||
if (std::isdigit(*pos) || *pos == '.') {
|
||||
auto number = std::strtold(pos, &pos);
|
||||
|
||||
if (*pos == 'x') {
|
||||
pos--;
|
||||
number = std::strtoull(pos, &pos, 0);
|
||||
}
|
||||
|
||||
inputQueue.push(Token{ .type = TokenType::Number, .number = number });
|
||||
} else if (*pos == '(') {
|
||||
inputQueue.push(Token{ .type = TokenType::Bracket, .bracketType = BracketType::Left});
|
||||
pos++;
|
||||
} else if (*pos == ')') {
|
||||
inputQueue.push(Token{ .type = TokenType::Bracket, .bracketType = BracketType::Right});
|
||||
pos++;
|
||||
} else if (std::isspace(*pos)) {
|
||||
pos++;
|
||||
} else {
|
||||
auto [op, width] = toOperator(pos);
|
||||
|
||||
if (op != Operator::Invalid) {
|
||||
inputQueue.push(Token{ .type = TokenType::Operator, .op = op });
|
||||
pos += width;
|
||||
} else {
|
||||
Token token;
|
||||
|
||||
while (std::isalpha(*pos) || *pos == '_') {
|
||||
token.name += *pos;
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (*pos == '(') {
|
||||
pos++;
|
||||
|
||||
u32 depth = 1;
|
||||
std::vector<std::string> expressions;
|
||||
expressions.emplace_back();
|
||||
|
||||
while (*pos != 0x00) {
|
||||
if (*pos == '(') depth++;
|
||||
else if (*pos == ')') depth--;
|
||||
|
||||
if (depth == 0)
|
||||
break;
|
||||
|
||||
if (depth == 1 && *pos == ',') {
|
||||
expressions.emplace_back();
|
||||
pos++;
|
||||
}
|
||||
|
||||
expressions.back() += *pos;
|
||||
|
||||
pos++;
|
||||
}
|
||||
|
||||
pos++;
|
||||
|
||||
for (const auto &expression : expressions) {
|
||||
if (expression == "" && expressions.size() > 1)
|
||||
throw std::invalid_argument("Invalid function call syntax!");
|
||||
else if (expression == "")
|
||||
break;
|
||||
|
||||
auto inputQueue = parseInput(expression.c_str());
|
||||
auto postfixTokens = toPostfix(inputQueue);
|
||||
auto result = evaluate(postfixTokens);
|
||||
|
||||
if (!result.has_value())
|
||||
throw std::invalid_argument("Invalid argument for function!");
|
||||
|
||||
token.arguments.push_back(result.value());
|
||||
}
|
||||
|
||||
token.type = TokenType::Function;
|
||||
inputQueue.push(token);
|
||||
|
||||
} else {
|
||||
token.type = TokenType::Variable;
|
||||
inputQueue.push(token);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (prevPos == pos)
|
||||
throw std::invalid_argument("Invalid syntax!");
|
||||
|
||||
prevPos = pos;
|
||||
}
|
||||
|
||||
return inputQueue;
|
||||
}
|
||||
|
||||
std::queue<Token> MathEvaluator::toPostfix(std::queue<Token> inputQueue) {
|
||||
std::queue<Token> outputQueue;
|
||||
std::stack<Token> operatorStack;
|
||||
|
||||
while (!inputQueue.empty()) {
|
||||
Token currToken = inputQueue.front();
|
||||
inputQueue.pop();
|
||||
|
||||
if (currToken.type == TokenType::Number || currToken.type == TokenType::Variable || currToken.type == TokenType::Function)
|
||||
outputQueue.push(currToken);
|
||||
else if (currToken.type == TokenType::Operator) {
|
||||
while ((!operatorStack.empty())
|
||||
&& (operatorStack.top().type == TokenType::Operator && currToken.type == TokenType::Operator && (comparePrecedence(operatorStack.top().op, currToken.op) > 0) || (comparePrecedence(operatorStack.top().op, currToken.op) == 0 && isLeftAssociative(currToken.op)))
|
||||
&& operatorStack.top().type != TokenType::Bracket) {
|
||||
outputQueue.push(operatorStack.top());
|
||||
operatorStack.pop();
|
||||
}
|
||||
operatorStack.push(currToken);
|
||||
} else if (currToken.type == TokenType::Bracket) {
|
||||
if (currToken.bracketType == BracketType::Left)
|
||||
operatorStack.push(currToken);
|
||||
else {
|
||||
if (operatorStack.empty())
|
||||
throw std::invalid_argument("Mismatching parenthesis!");
|
||||
|
||||
while (operatorStack.top().type != TokenType::Bracket || (operatorStack.top().type == TokenType::Bracket && operatorStack.top().bracketType != BracketType::Left)) {
|
||||
if (operatorStack.empty())
|
||||
throw std::invalid_argument("Mismatching parenthesis!");
|
||||
|
||||
outputQueue.push(operatorStack.top());
|
||||
operatorStack.pop();
|
||||
}
|
||||
|
||||
operatorStack.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (!operatorStack.empty()) {
|
||||
auto top = operatorStack.top();
|
||||
|
||||
if (top.type == TokenType::Bracket)
|
||||
throw std::invalid_argument("Mismatching parenthesis!");
|
||||
|
||||
outputQueue.push(top);
|
||||
operatorStack.pop();
|
||||
}
|
||||
|
||||
return outputQueue;
|
||||
}
|
||||
|
||||
std::optional<long double> MathEvaluator::evaluate(std::queue<Token> postfixTokens) {
|
||||
std::stack<long double> evaluationStack;
|
||||
|
||||
while (!postfixTokens.empty()) {
|
||||
auto front = postfixTokens.front();
|
||||
postfixTokens.pop();
|
||||
|
||||
if (front.type == TokenType::Number)
|
||||
evaluationStack.push(front.number);
|
||||
else if (front.type == TokenType::Operator) {
|
||||
long double rightOperand, leftOperand;
|
||||
if (evaluationStack.size() < 2) {
|
||||
if ((front.op == Operator::Addition || front.op == Operator::Subtraction || front.op == Operator::Not || front.op == Operator::BitwiseNot) && evaluationStack.size() == 1) {
|
||||
rightOperand = evaluationStack.top(); evaluationStack.pop();
|
||||
leftOperand = 0;
|
||||
}
|
||||
else throw std::invalid_argument("Not enough operands for operator!");
|
||||
} else {
|
||||
rightOperand = evaluationStack.top(); evaluationStack.pop();
|
||||
leftOperand = evaluationStack.top(); evaluationStack.pop();
|
||||
}
|
||||
|
||||
long double result = std::numeric_limits<long double>::quiet_NaN();
|
||||
switch (front.op) {
|
||||
default:
|
||||
case Operator::Invalid:
|
||||
throw std::invalid_argument("Invalid operator!");
|
||||
case Operator::And:
|
||||
result = static_cast<s64>(leftOperand) && static_cast<s64>(rightOperand);
|
||||
break;
|
||||
case Operator::Or:
|
||||
result = static_cast<s64>(leftOperand) && static_cast<s64>(rightOperand);
|
||||
break;
|
||||
case Operator::Xor:
|
||||
result = (static_cast<s64>(leftOperand) ^ static_cast<s64>(rightOperand)) > 0;
|
||||
break;
|
||||
case Operator::GreaterThan:
|
||||
result = leftOperand > rightOperand;
|
||||
break;
|
||||
case Operator::LessThan:
|
||||
result = leftOperand < rightOperand;
|
||||
break;
|
||||
case Operator::GreaterThanOrEquals:
|
||||
result = leftOperand >= rightOperand;
|
||||
break;
|
||||
case Operator::LessThanOrEquals:
|
||||
result = leftOperand <= rightOperand;
|
||||
break;
|
||||
case Operator::Equals:
|
||||
result = leftOperand == rightOperand;
|
||||
break;
|
||||
case Operator::NotEquals:
|
||||
result = leftOperand != rightOperand;
|
||||
break;
|
||||
case Operator::Not:
|
||||
result = !static_cast<s64>(rightOperand);
|
||||
break;
|
||||
case Operator::BitwiseOr:
|
||||
result = static_cast<s64>(leftOperand) | static_cast<s64>(rightOperand);
|
||||
break;
|
||||
case Operator::BitwiseXor:
|
||||
result = static_cast<s64>(leftOperand) ^ static_cast<s64>(rightOperand);
|
||||
break;
|
||||
case Operator::BitwiseAnd:
|
||||
result = static_cast<s64>(leftOperand) & static_cast<s64>(rightOperand);
|
||||
break;
|
||||
case Operator::BitwiseNot:
|
||||
result = ~static_cast<s64>(rightOperand);
|
||||
break;
|
||||
case Operator::ShiftLeft:
|
||||
result = static_cast<s64>(leftOperand) << static_cast<s64>(rightOperand);
|
||||
break;
|
||||
case Operator::ShiftRight:
|
||||
result = static_cast<s64>(leftOperand) >> static_cast<s64>(rightOperand);
|
||||
break;
|
||||
case Operator::Addition:
|
||||
result = leftOperand + rightOperand;
|
||||
break;
|
||||
case Operator::Subtraction:
|
||||
result = leftOperand - rightOperand;
|
||||
break;
|
||||
case Operator::Multiplication:
|
||||
result = leftOperand * rightOperand;
|
||||
break;
|
||||
case Operator::Division:
|
||||
result = leftOperand / rightOperand;
|
||||
break;
|
||||
case Operator::Modulus:
|
||||
result = std::fmod(leftOperand, rightOperand);
|
||||
break;
|
||||
case Operator::Exponentiation:
|
||||
result = std::pow(leftOperand, rightOperand);
|
||||
break;
|
||||
case Operator::Combine:
|
||||
result = (static_cast<u64>(leftOperand) << (64 - __builtin_clzll(static_cast<u64>(rightOperand)))) | static_cast<u64>(rightOperand);
|
||||
break;
|
||||
}
|
||||
|
||||
evaluationStack.push(result);
|
||||
} else if (front.type == TokenType::Variable) {
|
||||
if (this->m_variables.contains(front.name))
|
||||
evaluationStack.push(this->m_variables.at(front.name));
|
||||
else
|
||||
throw std::invalid_argument("Unknown variable!");
|
||||
} else if (front.type == TokenType::Function) {
|
||||
if (!this->m_functions[front.name])
|
||||
throw std::invalid_argument("Unknown function called!");
|
||||
|
||||
auto result = this->m_functions[front.name](front.arguments);
|
||||
|
||||
if (result.has_value())
|
||||
evaluationStack.push(result.value());
|
||||
} else
|
||||
throw std::invalid_argument("Parenthesis in postfix expression!");
|
||||
|
||||
}
|
||||
|
||||
if (evaluationStack.empty())
|
||||
return { };
|
||||
else if (evaluationStack.size() > 1)
|
||||
throw std::invalid_argument("Undigested input left!");
|
||||
else
|
||||
return evaluationStack.top();
|
||||
}
|
||||
|
||||
|
||||
std::optional<long double> MathEvaluator::evaluate(std::string input) {
|
||||
auto inputQueue = parseInput(input.c_str());
|
||||
|
||||
std::string resultVariable = "ans";
|
||||
|
||||
{
|
||||
std::queue<Token> queueCopy = inputQueue;
|
||||
if (queueCopy.front().type == TokenType::Variable) {
|
||||
resultVariable = queueCopy.front().name;
|
||||
queueCopy.pop();
|
||||
if (queueCopy.front().type != TokenType::Operator || queueCopy.front().op != Operator::Assign)
|
||||
resultVariable = "ans";
|
||||
else {
|
||||
inputQueue.pop();
|
||||
inputQueue.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto postfixTokens = toPostfix(inputQueue);
|
||||
|
||||
auto result = evaluate(postfixTokens);
|
||||
|
||||
if (result.has_value()) {
|
||||
this->setVariable(resultVariable, result.value());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void MathEvaluator::setVariable(std::string name, long double value) {
|
||||
this->m_variables[name] = value;
|
||||
}
|
||||
|
||||
void MathEvaluator::setFunction(std::string name, std::function<std::optional<long double>(std::vector<long double>)> function, size_t minNumArgs, size_t maxNumArgs) {
|
||||
this->m_functions[name] = [minNumArgs, maxNumArgs, function](auto args) {
|
||||
if (args.size() < minNumArgs || args.size() > maxNumArgs)
|
||||
throw std::invalid_argument("Invalid number of function arguments!");
|
||||
|
||||
return function(args);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
void MathEvaluator::registerStandardVariables() {
|
||||
this->setVariable("ans", 0);
|
||||
}
|
||||
|
||||
void MathEvaluator::registerStandardFunctions() {
|
||||
this->setFunction("sin", [](auto args){ return std::sin(args[0]); }, 1, 1);
|
||||
this->setFunction("cos", [](auto args){ return std::cos(args[0]); }, 1, 1);
|
||||
this->setFunction("tan", [](auto args){ return std::tan(args[0]); }, 1, 1);
|
||||
this->setFunction("sqrt", [](auto args){ return std::sqrt(args[0]); }, 1, 1);
|
||||
this->setFunction("ceil", [](auto args){ return std::ceil(args[0]); }, 1, 1);
|
||||
this->setFunction("floor", [](auto args){ return std::floor(args[0]); }, 1, 1);
|
||||
this->setFunction("sign", [](auto args){ return (args[0] > 0) ? 1 : (args[0] == 0) ? 0 : -1; }, 1, 1);
|
||||
this->setFunction("abs", [](auto args){ return std::abs(args[0]); }, 1, 1);
|
||||
this->setFunction("ln", [](auto args){ return std::log(args[0]); }, 1, 1);
|
||||
this->setFunction("lb", [](auto args){ return std::log2(args[0]); }, 1, 1);
|
||||
this->setFunction("log", [](auto args){ return args.size() == 1 ? std::log10(args[0]) : std::log(args[1]) / std::log(args[0]); }, 1, 2);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
#include "patches.hpp"
|
||||
#include "helpers/patches.hpp"
|
||||
|
||||
#include <concepts>
|
||||
#include <cstring>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
#include "utils.hpp"
|
||||
#include "helpers/utils.hpp"
|
||||
|
||||
namespace hex {
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include "utils.hpp"
|
||||
#include "helpers/utils.hpp"
|
||||
|
||||
#include <codecvt>
|
||||
#include <locale>
|
@ -1,6 +1,6 @@
|
||||
#include "lang/parser.hpp"
|
||||
|
||||
#include "utils.hpp"
|
||||
#include "helpers/utils.hpp"
|
||||
|
||||
#include <optional>
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include <unordered_set>
|
||||
#include <string>
|
||||
|
||||
#include "utils.hpp"
|
||||
#include "helpers/utils.hpp"
|
||||
|
||||
namespace hex::lang {
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "utils.hpp"
|
||||
#include "helpers/utils.hpp"
|
||||
|
||||
namespace hex::prv {
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "views/view_data_inspector.hpp"
|
||||
|
||||
#include "providers/provider.hpp"
|
||||
#include "utils.hpp"
|
||||
#include "helpers/utils.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "views/view_disassembler.hpp"
|
||||
|
||||
#include "providers/provider.hpp"
|
||||
#include "utils.hpp"
|
||||
#include "helpers/utils.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
@ -2,11 +2,11 @@
|
||||
|
||||
#include "providers/provider.hpp"
|
||||
|
||||
#include "crypto.hpp"
|
||||
#include "helpers/crypto.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "utils.hpp"
|
||||
#include "helpers/utils.hpp"
|
||||
|
||||
namespace hex {
|
||||
|
||||
|
@ -5,8 +5,8 @@
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include "crypto.hpp"
|
||||
#include "patches.hpp"
|
||||
#include "helpers/crypto.hpp"
|
||||
#include "helpers/patches.hpp"
|
||||
|
||||
#undef __STRICT_ANSI__
|
||||
#include <cstdio>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include "providers/provider.hpp"
|
||||
|
||||
#include "utils.hpp"
|
||||
#include "helpers/utils.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "lang/lexer.hpp"
|
||||
#include "lang/validator.hpp"
|
||||
#include "lang/evaluator.hpp"
|
||||
#include "utils.hpp"
|
||||
#include "helpers/utils.hpp"
|
||||
|
||||
#include <magic.h>
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "views/view_strings.hpp"
|
||||
|
||||
#include "providers/provider.hpp"
|
||||
#include "utils.hpp"
|
||||
#include "helpers/utils.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
@ -2,8 +2,9 @@
|
||||
|
||||
#include <cstring>
|
||||
#include <regex>
|
||||
#include <optional>
|
||||
|
||||
#include "utils.hpp"
|
||||
#include "helpers/utils.hpp"
|
||||
|
||||
#include <llvm/Demangle/Demangle.h>
|
||||
|
||||
@ -11,7 +12,6 @@ namespace hex {
|
||||
|
||||
ViewTools::ViewTools() : View("Tools") {
|
||||
this->m_mangledBuffer = new char[0xF'FFFF];
|
||||
|
||||
std::memset(this->m_mangledBuffer, 0x00, 0xF'FFFF);
|
||||
|
||||
this->m_regexInput = new char[0xF'FFFF];
|
||||
@ -20,6 +20,19 @@ namespace hex {
|
||||
std::memset(this->m_regexInput, 0x00, 0xF'FFFF);
|
||||
std::memset(this->m_regexPattern, 0x00, 0xF'FFFF);
|
||||
std::memset(this->m_replacePattern, 0x00, 0xF'FFFF);
|
||||
|
||||
|
||||
this->m_mathInput = new char[0xFFFF];
|
||||
std::memset(this->m_mathInput, 0x00, 0xFFFF);
|
||||
this->m_mathEvaluator.registerStandardVariables();
|
||||
this->m_mathEvaluator.registerStandardFunctions();
|
||||
this->m_mathEvaluator.setFunction("clear", [this](auto args) -> std::optional<long double> {
|
||||
this->m_mathHistory.clear();
|
||||
this->m_lastMathError.clear();
|
||||
std::memset(this->m_mathInput, 0x00, 0xFFFF);
|
||||
|
||||
return { };
|
||||
}, 0, 0);
|
||||
}
|
||||
|
||||
ViewTools::~ViewTools() {
|
||||
@ -28,6 +41,8 @@ namespace hex {
|
||||
delete[] this->m_regexInput;
|
||||
delete[] this->m_regexPattern;
|
||||
delete[] this->m_replacePattern;
|
||||
|
||||
delete[] this->m_mathInput;
|
||||
}
|
||||
|
||||
void ViewTools::drawDemangler() {
|
||||
@ -124,12 +139,131 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
void ViewTools::drawMathEvaluator() {
|
||||
if (ImGui::CollapsingHeader("Calculator")) {
|
||||
if (ImGui::InputText("Input", this->m_mathInput, 0xFFFF, ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll)) {
|
||||
ImGui::SetKeyboardFocusHere();
|
||||
std::optional<long double> result;
|
||||
|
||||
try {
|
||||
result = this->m_mathEvaluator.evaluate(this->m_mathInput);
|
||||
} catch (std::invalid_argument &e) {
|
||||
this->m_lastMathError = e.what();
|
||||
}
|
||||
|
||||
if (result.has_value()) {
|
||||
this->m_mathHistory.push_back(result.value());
|
||||
std::memset(this->m_mathInput, 0x00, 0xFFFF);
|
||||
this->m_lastMathError.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!this->m_lastMathError.empty())
|
||||
ImGui::TextColored(ImColor(0xA00040FF), "Last Error: %s", this->m_lastMathError.c_str());
|
||||
else
|
||||
ImGui::NewLine();
|
||||
|
||||
enum class MathDisplayType { Standard, Scientific, Programmer } mathDisplayType;
|
||||
if (ImGui::BeginTabBar("##mathFormatTabBar")) {
|
||||
if (ImGui::BeginTabItem("Standard")) {
|
||||
mathDisplayType = MathDisplayType::Standard;
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ImGui::BeginTabItem("Scientific")) {
|
||||
mathDisplayType = MathDisplayType::Scientific;
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ImGui::BeginTabItem("Programmer")) {
|
||||
mathDisplayType = MathDisplayType::Programmer;
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
|
||||
if (ImGui::BeginTable("##mathWrapper", 2)) {
|
||||
ImGui::TableSetupColumn("##results");
|
||||
ImGui::TableSetupColumn("##variables", ImGuiTableColumnFlags_WidthStretch, 0.7);
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::BeginTable("##mathHistory", 1, ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(0, 400))) {
|
||||
ImGui::TableSetupScrollFreeze(0, 1);
|
||||
ImGui::TableSetupColumn("History");
|
||||
|
||||
ImGuiListClipper clipper;
|
||||
clipper.Begin(this->m_mathHistory.size());
|
||||
|
||||
ImGui::TableHeadersRow();
|
||||
while (clipper.Step()) {
|
||||
for (u64 i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
switch (mathDisplayType) {
|
||||
case MathDisplayType::Standard:
|
||||
ImGui::Text("%.3Lf", this->m_mathHistory[(this->m_mathHistory.size() - 1) - i]);
|
||||
break;
|
||||
case MathDisplayType::Scientific:
|
||||
ImGui::Text("%.6Le", this->m_mathHistory[(this->m_mathHistory.size() - 1) - i]);
|
||||
break;
|
||||
case MathDisplayType::Programmer:
|
||||
ImGui::Text("0x%llX (%llu)",
|
||||
u64(this->m_mathHistory[(this->m_mathHistory.size() - 1) - i]),
|
||||
u64(this->m_mathHistory[(this->m_mathHistory.size() - 1) - i]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clipper.End();
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::BeginTable("##mathVariables", 2, ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(0, 400))) {
|
||||
ImGui::TableSetupScrollFreeze(0, 1);
|
||||
ImGui::TableSetupColumn("Name");
|
||||
ImGui::TableSetupColumn("Value");
|
||||
|
||||
ImGui::TableHeadersRow();
|
||||
for (const auto &[name, value] : this->m_mathEvaluator.getVariables()) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(name.c_str());
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
switch (mathDisplayType) {
|
||||
case MathDisplayType::Standard:
|
||||
ImGui::Text("%.3Lf", value);
|
||||
break;
|
||||
case MathDisplayType::Scientific:
|
||||
ImGui::Text("%.6Le", value);
|
||||
break;
|
||||
case MathDisplayType::Programmer:
|
||||
ImGui::Text("0x%llX (%llu)", u64(value), u64(value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void ViewTools::createView() {
|
||||
if (ImGui::Begin("Tools", &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) {
|
||||
|
||||
this->drawDemangler();
|
||||
this->drawASCIITable();
|
||||
this->drawRegexReplacer();
|
||||
this->drawMathEvaluator();
|
||||
this->drawColorPicker();
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user