Mesen/Core/ExpressionEvaluator.h

144 lines
3.8 KiB
C++

#pragma once
#include "stdafx.h"
#include <stack>
#include <deque>
#include <unordered_map>
#include <unordered_set>
#include "../Utilities/SimpleLock.h"
#include "DebuggerTypes.h"
class Debugger;
enum EvalOperators : int64_t
{
//Binary operators
Multiplication = 20000000000,
Division = 20000000001,
Modulo = 20000000002,
Addition = 20000000003,
Substration = 20000000004,
ShiftLeft = 20000000005,
ShiftRight = 20000000006,
SmallerThan = 20000000007,
SmallerOrEqual = 20000000008,
GreaterThan = 20000000009,
GreaterOrEqual = 20000000010,
Equal = 20000000011,
NotEqual = 20000000012,
BinaryAnd = 20000000013,
BinaryXor = 20000000014,
BinaryOr = 20000000015,
LogicalAnd = 20000000016,
LogicalOr = 20000000017,
//Unary operators
Plus = 20000000050,
Minus = 20000000051,
BinaryNot = 20000000052,
LogicalNot = 20000000053,
AbsoluteAddress = 20000000054,
//Used to read ram address
Bracket = 20000000060, //Read byte
Braces = 20000000061, //Read word
//Special value, not used as an operator
Parenthesis = 20000000100,
};
enum EvalValues : int64_t
{
RegA = 20000000100,
RegX = 20000000101,
RegY = 20000000102,
RegSP = 20000000103,
RegPS = 20000000104,
RegPC = 20000000105,
RegOpPC = 20000000106,
PpuFrameCount = 20000000107,
PpuCycle = 20000000108,
PpuScanline = 20000000109,
Nmi = 20000000110,
Irq = 20000000111,
Value = 20000000112,
Address = 20000000113,
IsWrite = 20000000115,
IsRead = 20000000116,
PreviousOpPC = 20000000117,
Sprite0Hit = 20000000118,
SpriteOverflow = 20000000119,
VerticalBlank = 20000000120,
Branched = 20000000121,
RegPS_Carry = 20000000122,
RegPS_Zero = 20000000123,
RegPS_Interrupt = 20000000124,
RegPS_Decimal = 20000000125,
RegPS_Overflow = 20000000126,
RegPS_Negative = 20000000127,
FirstLabelIndex = 20000002000,
};
enum EvalResultType : int32_t
{
Numeric = 0,
Boolean = 1,
Invalid = 2,
DivideBy0 = 3,
OutOfScope = 4
};
class StringHasher
{
public:
size_t operator()(const std::string& t) const
{
//Quick hash for expressions - most are likely to have different lengths, and not expecting dozens of breakpoints, either, so this should be fine.
return t.size();
}
};
struct ExpressionData
{
std::vector<int64_t> RpnQueue;
std::vector<string> Labels;
};
class ExpressionEvaluator
{
private:
static const vector<string> _binaryOperators;
static const vector<int> _binaryPrecedence;
static const vector<string> _unaryOperators;
static const vector<int> _unaryPrecedence;
static const std::unordered_set<string> _operators;
std::unordered_map<string, ExpressionData, StringHasher> _cache;
SimpleLock _cacheLock;
int64_t operandStack[1000];
Debugger* _debugger;
bool IsOperator(string token, int &precedence, bool unaryOperator);
EvalOperators GetOperator(string token, bool unaryOperator);
bool CheckSpecialTokens(string expression, size_t &pos, string &output, ExpressionData &data);
string GetNextToken(string expression, size_t &pos, ExpressionData &data, bool &success, bool previousTokenIsOp);
bool ProcessSpecialOperator(EvalOperators evalOp, std::stack<EvalOperators> &opStack, std::stack<int> &precedenceStack, vector<int64_t> &outputQueue);
bool ToRpn(string expression, ExpressionData &data);
int32_t PrivateEvaluate(string expression, DebugState &state, EvalResultType &resultType, OperationInfo &operationInfo, bool &success);
ExpressionData* PrivateGetRpnList(string expression, bool& success);
public:
ExpressionEvaluator(Debugger* debugger);
int32_t Evaluate(ExpressionData &data, DebugState &state, EvalResultType &resultType, OperationInfo &operationInfo);
int32_t Evaluate(string expression, DebugState &state, EvalResultType &resultType, OperationInfo &operationInfo);
ExpressionData GetRpnList(string expression, bool &success);
bool Validate(string expression);
#if _DEBUG
void RunTests();
#endif
};