Play-/Source/ui_qt/DebugSupport/DebugExpressionEvaluator.cpp
2021-01-07 21:47:30 +00:00

199 lines
3.8 KiB
C++

#include "DebugExpressionEvaluator.h"
#include <ctype.h>
#include <assert.h>
uint32 CDebugExpressionEvaluator::Evaluate(const char* expression, CMIPS* context)
{
TokenArray tokens = Parse(expression);
uint32 result = Evaluate(tokens, context);
return result;
}
CDebugExpressionEvaluator::TokenArray CDebugExpressionEvaluator::Parse(const char* expression)
{
TokenArray tokens;
TOKEN currentToken;
currentToken.type = TOKEN_TYPE_INVALID;
while(1)
{
char currChar = (*expression++);
if(currChar == 0)
{
if(currentToken.type != TOKEN_TYPE_INVALID)
{
tokens.push_back(currentToken);
currentToken.type = TOKEN_TYPE_INVALID;
}
break;
}
else if(currChar == ' ' || currChar == '\t')
{
if(currentToken.type != TOKEN_TYPE_INVALID)
{
tokens.push_back(currentToken);
currentToken.type = TOKEN_TYPE_INVALID;
}
}
else if(currChar == '+' || currChar == '-' || currChar == '*' || currChar == '/')
{
if(currentToken.type != TOKEN_TYPE_INVALID)
{
tokens.push_back(currentToken);
currentToken.type = TOKEN_TYPE_INVALID;
}
currentToken.type = TOKEN_TYPE_OP;
currentToken.value = currChar;
tokens.push_back(currentToken);
currentToken.type = TOKEN_TYPE_INVALID;
}
else if(currentToken.type == TOKEN_TYPE_INVALID)
{
if(isdigit(currChar))
{
currentToken.type = TOKEN_TYPE_NUMBER;
currentToken.value = currChar;
}
else
{
currentToken.type = TOKEN_TYPE_SYMBOL;
currentToken.value = currChar;
}
}
else if(currentToken.type != TOKEN_TYPE_INVALID)
{
currentToken.value += currChar;
}
else
{
assert(0);
}
}
return tokens;
}
uint32 CDebugExpressionEvaluator::Evaluate(const TokenArray& tokens, CMIPS* context)
{
OP_TYPE opType = OP_FIRST;
uint32 result = 0;
uint32 operand = 0;
for(TokenArray::const_iterator tokenIterator(tokens.begin());
tokens.end() != tokenIterator; tokenIterator++)
{
const TOKEN& token(*tokenIterator);
switch(token.type)
{
case TOKEN_TYPE_NUMBER:
{
uint32 value = 0;
if(token.value.find("0x") != std::string::npos)
{
if(sscanf(token.value.c_str(), "%x", &value) != 1)
{
throw std::runtime_error("Couldn't parse number.");
}
}
else
{
if(sscanf(token.value.c_str(), "%d", &value) != 1)
{
throw std::runtime_error("Couldn't parse number.");
}
}
operand = value;
}
break;
case TOKEN_TYPE_SYMBOL:
{
uint32 value = 0;
bool found = false;
for(unsigned int i = 0; i < 32; i++)
{
if(!token.value.compare(CMIPS::m_sGPRName[i]))
{
value = context->m_State.nGPR[i].nV0;
found = true;
}
}
if(!found)
{
std::string message = std::string("Unknown symbol '");
message += token.value;
message += std::string("'.");
throw std::runtime_error(message);
}
operand = value;
}
break;
case TOKEN_TYPE_OP:
{
if(opType != OP_INVALID)
{
throw std::runtime_error("Invalid expression.");
}
if(!token.value.compare("+"))
{
opType = OP_ADD;
}
else if(!token.value.compare("-"))
{
opType = OP_SUB;
}
else if(!token.value.compare("*"))
{
opType = OP_MUL;
}
else if(!token.value.compare("/"))
{
opType = OP_DIV;
}
else
{
throw std::runtime_error("Unknown operator type.");
}
}
break;
default:
assert(0);
break;
}
if(token.type != TOKEN_TYPE_OP)
{
switch(opType)
{
case OP_FIRST:
result = operand;
break;
case OP_ADD:
result += operand;
break;
case OP_SUB:
result -= operand;
break;
case OP_MUL:
result *= operand;
break;
case OP_DIV:
result /= operand;
break;
case OP_INVALID:
throw std::runtime_error("Invalid expression (missing operator).");
break;
default:
assert(0);
break;
}
opType = OP_INVALID;
}
}
return result;
}