Debugger: Fixed emulator crash when entering some invalid watch/debug expressions
This commit is contained in:
parent
c9c55b2c7e
commit
c317179afc
2 changed files with 71 additions and 30 deletions
|
@ -171,12 +171,37 @@ string ExpressionEvaluator::GetNextToken(string expression, size_t &pos)
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpressionEvaluator::ToRpn(string expression, vector<int> &outputQueue)
|
bool ExpressionEvaluator::ProcessSpecialOperator(EvalOperators evalOp, std::stack<EvalOperators> &opStack, vector<int> &outputQueue)
|
||||||
|
{
|
||||||
|
if(opStack.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
while(opStack.top() != evalOp) {
|
||||||
|
outputQueue.push_back(opStack.top());
|
||||||
|
opStack.pop();
|
||||||
|
|
||||||
|
if(opStack.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(evalOp != EvalOperators::Parenthesis) {
|
||||||
|
outputQueue.push_back(opStack.top());
|
||||||
|
}
|
||||||
|
opStack.pop();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExpressionEvaluator::ToRpn(string expression, vector<int> &outputQueue)
|
||||||
{
|
{
|
||||||
std::stack<EvalOperators> opStack = std::stack<EvalOperators>();
|
std::stack<EvalOperators> opStack = std::stack<EvalOperators>();
|
||||||
std::stack<int> precedenceStack;
|
std::stack<int> precedenceStack;
|
||||||
|
|
||||||
size_t position = 0;
|
size_t position = 0;
|
||||||
|
int parenthesisCount = 0;
|
||||||
|
int bracketCount = 0;
|
||||||
|
int braceCount = 0;
|
||||||
|
|
||||||
bool previousTokenIsOp = true;
|
bool previousTokenIsOp = true;
|
||||||
while(true) {
|
while(true) {
|
||||||
string token = GetNextToken(expression, position);
|
string token = GetNextToken(expression, position);
|
||||||
|
@ -203,44 +228,49 @@ void ExpressionEvaluator::ToRpn(string expression, vector<int> &outputQueue)
|
||||||
|
|
||||||
previousTokenIsOp = true;
|
previousTokenIsOp = true;
|
||||||
} else if(token[0] == '(') {
|
} else if(token[0] == '(') {
|
||||||
|
parenthesisCount++;
|
||||||
opStack.push(EvalOperators::Parenthesis);
|
opStack.push(EvalOperators::Parenthesis);
|
||||||
precedenceStack.push(0);
|
precedenceStack.push(0);
|
||||||
previousTokenIsOp = true;
|
previousTokenIsOp = true;
|
||||||
} else if(token[0] == ')') {
|
} else if(token[0] == ')') {
|
||||||
while(opStack.top() != EvalOperators::Parenthesis) {
|
parenthesisCount--;
|
||||||
outputQueue.push_back(opStack.top());
|
if(!ProcessSpecialOperator(EvalOperators::Parenthesis, opStack, outputQueue)) {
|
||||||
opStack.pop();
|
return false;
|
||||||
}
|
}
|
||||||
opStack.pop();
|
|
||||||
} else if(token[0] == '[') {
|
} else if(token[0] == '[') {
|
||||||
|
bracketCount++;
|
||||||
opStack.push(EvalOperators::Bracket);
|
opStack.push(EvalOperators::Bracket);
|
||||||
precedenceStack.push(0);
|
precedenceStack.push(0);
|
||||||
} else if(token[0] == ']') {
|
} else if(token[0] == ']') {
|
||||||
while(opStack.top() != EvalOperators::Bracket) {
|
bracketCount--;
|
||||||
outputQueue.push_back(opStack.top());
|
if(!ProcessSpecialOperator(EvalOperators::Bracket, opStack, outputQueue)) {
|
||||||
opStack.pop();
|
return false;
|
||||||
}
|
}
|
||||||
outputQueue.push_back(opStack.top());
|
|
||||||
opStack.pop();
|
|
||||||
} else if(token[0] == '{') {
|
} else if(token[0] == '{') {
|
||||||
|
braceCount++;
|
||||||
opStack.push(EvalOperators::Braces);
|
opStack.push(EvalOperators::Braces);
|
||||||
precedenceStack.push(0);
|
precedenceStack.push(0);
|
||||||
} else if(token[0] == '}') {
|
} else if(token[0] == '}') {
|
||||||
while(opStack.top() != EvalOperators::Braces) {
|
braceCount--;
|
||||||
outputQueue.push_back(opStack.top());
|
if(!ProcessSpecialOperator(EvalOperators::Braces, opStack, outputQueue)){
|
||||||
opStack.pop();
|
return false;
|
||||||
}
|
}
|
||||||
outputQueue.push_back(opStack.top());
|
|
||||||
opStack.pop();
|
|
||||||
} else {
|
} else {
|
||||||
outputQueue.push_back(std::stoi(token));
|
outputQueue.push_back(std::stoi(token));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(braceCount || bracketCount || parenthesisCount) {
|
||||||
|
//Mismatching number of brackets/braces/parenthesis
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
while(!opStack.empty()) {
|
while(!opStack.empty()) {
|
||||||
outputQueue.push_back(opStack.top());
|
outputQueue.push_back(opStack.top());
|
||||||
opStack.pop();
|
opStack.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t ExpressionEvaluator::EvaluateExpression(vector<int> *outputQueue, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr)
|
int32_t ExpressionEvaluator::EvaluateExpression(vector<int> *outputQueue, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr)
|
||||||
|
@ -318,8 +348,9 @@ ExpressionEvaluator::ExpressionEvaluator(Debugger* debugger)
|
||||||
_debugger = debugger;
|
_debugger = debugger;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t ExpressionEvaluator::PrivateEvaluate(string expression, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr)
|
int32_t ExpressionEvaluator::PrivateEvaluate(string expression, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr, bool& success)
|
||||||
{
|
{
|
||||||
|
success = true;
|
||||||
vector<int> output;
|
vector<int> output;
|
||||||
vector<int> *outputQueue = nullptr;
|
vector<int> *outputQueue = nullptr;
|
||||||
|
|
||||||
|
@ -335,14 +366,18 @@ int32_t ExpressionEvaluator::PrivateEvaluate(string expression, DebugState &stat
|
||||||
if(outputQueue == nullptr && output.empty()) {
|
if(outputQueue == nullptr && output.empty()) {
|
||||||
string fixedExp = expression;
|
string fixedExp = expression;
|
||||||
fixedExp.erase(std::remove(fixedExp.begin(), fixedExp.end(), ' '), fixedExp.end());
|
fixedExp.erase(std::remove(fixedExp.begin(), fixedExp.end(), ' '), fixedExp.end());
|
||||||
ToRpn(fixedExp, output);
|
success = ToRpn(fixedExp, output);
|
||||||
|
|
||||||
if(_containsCustomLabels) {
|
if(success) {
|
||||||
outputQueue = &output;
|
if(_containsCustomLabels) {
|
||||||
|
outputQueue = &output;
|
||||||
|
} else {
|
||||||
|
LockHandler lock = _cacheLock.AcquireSafe();
|
||||||
|
_outputCache[expression] = output;
|
||||||
|
outputQueue = &_outputCache[expression];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
LockHandler lock = _cacheLock.AcquireSafe();
|
return 0;
|
||||||
_outputCache[expression] = output;
|
|
||||||
outputQueue = &_outputCache[expression];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,11 +397,16 @@ int32_t ExpressionEvaluator::Evaluate(string expression, DebugState &state, int1
|
||||||
int32_t ExpressionEvaluator::Evaluate(string expression, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr)
|
int32_t ExpressionEvaluator::Evaluate(string expression, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return PrivateEvaluate(expression, state, resultType, memoryValue, memoryAddr);
|
bool success;
|
||||||
|
int32_t result = PrivateEvaluate(expression, state, resultType, memoryValue, memoryAddr, success);
|
||||||
|
if(success) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
} catch(std::exception e) {
|
} catch(std::exception e) {
|
||||||
resultType = EvalResultType::Invalid;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
resultType = EvalResultType::Invalid;
|
||||||
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExpressionEvaluator::Validate(string expression)
|
bool ExpressionEvaluator::Validate(string expression)
|
||||||
|
@ -374,8 +414,9 @@ bool ExpressionEvaluator::Validate(string expression)
|
||||||
try {
|
try {
|
||||||
DebugState state;
|
DebugState state;
|
||||||
EvalResultType type;
|
EvalResultType type;
|
||||||
PrivateEvaluate(expression, state, type, 0, 0);
|
bool success;
|
||||||
return true;
|
PrivateEvaluate(expression, state, type, 0, 0, success);
|
||||||
|
return success;
|
||||||
} catch(std::exception e) {
|
} catch(std::exception e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,12 +93,12 @@ private:
|
||||||
|
|
||||||
bool IsOperator(string token, int &precedence, bool unaryOperator);
|
bool IsOperator(string token, int &precedence, bool unaryOperator);
|
||||||
EvalOperators GetOperator(string token, bool unaryOperator);
|
EvalOperators GetOperator(string token, bool unaryOperator);
|
||||||
int GetOperatorPrecendence(string token);
|
|
||||||
bool CheckSpecialTokens(string expression, size_t &pos, string &output);
|
bool CheckSpecialTokens(string expression, size_t &pos, string &output);
|
||||||
string GetNextToken(string expression, size_t &pos);
|
string GetNextToken(string expression, size_t &pos);
|
||||||
void ToRpn(string expression, vector<int> &outputQueue);
|
bool ProcessSpecialOperator(EvalOperators evalOp, std::stack<EvalOperators> &opStack, vector<int> &outputQueue);
|
||||||
|
bool ToRpn(string expression, vector<int> &outputQueue);
|
||||||
int32_t EvaluateExpression(vector<int> *outputQueue, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr);
|
int32_t EvaluateExpression(vector<int> *outputQueue, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr);
|
||||||
int32_t PrivateEvaluate(string expression, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr);
|
int32_t PrivateEvaluate(string expression, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr, bool &success);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ExpressionEvaluator(Debugger* debugger);
|
ExpressionEvaluator(Debugger* debugger);
|
||||||
|
|
Loading…
Add table
Reference in a new issue