Debugger: Make the expression parser thread safe

This commit is contained in:
chaoticgd 2024-11-12 22:56:19 +00:00 committed by Ty
parent 8132a8a7f8
commit efb43ac7f9
10 changed files with 97 additions and 93 deletions

View File

@ -80,6 +80,8 @@ void BreakpointDialog::onRdoButtonToggled()
void BreakpointDialog::accept() void BreakpointDialog::accept()
{ {
std::string error;
if (m_purpose == PURPOSE::CREATE) if (m_purpose == PURPOSE::CREATE)
{ {
if (m_ui.rdoExecute->isChecked()) if (m_ui.rdoExecute->isChecked())
@ -93,9 +95,9 @@ void BreakpointDialog::accept()
PostfixExpression expr; PostfixExpression expr;
u64 address; u64 address;
if (!m_cpu->evaluateExpression(m_ui.txtAddress->text().toStdString().c_str(), address)) if (!m_cpu->evaluateExpression(m_ui.txtAddress->text().toStdString().c_str(), address, error))
{ {
QMessageBox::warning(this, tr("Invalid Address"), getExpressionError()); QMessageBox::warning(this, tr("Invalid Address"), QString::fromStdString(error));
return; return;
} }
@ -108,9 +110,9 @@ void BreakpointDialog::accept()
bp->hasCond = true; bp->hasCond = true;
bp->cond.debug = m_cpu; bp->cond.debug = m_cpu;
if (!m_cpu->initExpression(m_ui.txtCondition->text().toStdString().c_str(), expr)) if (!m_cpu->initExpression(m_ui.txtCondition->text().toStdString().c_str(), expr, error))
{ {
QMessageBox::warning(this, tr("Invalid Condition"), getExpressionError()); QMessageBox::warning(this, tr("Invalid Condition"), QString::fromStdString(error));
return; return;
} }
@ -121,16 +123,16 @@ void BreakpointDialog::accept()
if (auto* mc = std::get_if<MemCheck>(&m_bp_mc)) if (auto* mc = std::get_if<MemCheck>(&m_bp_mc))
{ {
u64 startAddress; u64 startAddress;
if (!m_cpu->evaluateExpression(m_ui.txtAddress->text().toStdString().c_str(), startAddress)) if (!m_cpu->evaluateExpression(m_ui.txtAddress->text().toStdString().c_str(), startAddress, error))
{ {
QMessageBox::warning(this, tr("Invalid Address"), getExpressionError()); QMessageBox::warning(this, tr("Invalid Address"), QString::fromStdString(error));
return; return;
} }
u64 size; u64 size;
if (!m_cpu->evaluateExpression(m_ui.txtSize->text().toStdString().c_str(), size) || !size) if (!m_cpu->evaluateExpression(m_ui.txtSize->text().toStdString().c_str(), size, error) || !size)
{ {
QMessageBox::warning(this, tr("Invalid Size"), getExpressionError()); QMessageBox::warning(this, tr("Invalid Size"), QString::fromStdString(error));
return; return;
} }
@ -143,9 +145,9 @@ void BreakpointDialog::accept()
mc->cond.debug = m_cpu; mc->cond.debug = m_cpu;
PostfixExpression expr; PostfixExpression expr;
if (!m_cpu->initExpression(m_ui.txtCondition->text().toStdString().c_str(), expr)) if (!m_cpu->initExpression(m_ui.txtCondition->text().toStdString().c_str(), expr, error))
{ {
QMessageBox::warning(this, tr("Invalid Condition"), getExpressionError()); QMessageBox::warning(this, tr("Invalid Condition"), QString::fromStdString(error));
return; return;
} }

View File

@ -170,9 +170,10 @@ void DisassemblyWidget::contextGoToAddress()
return; return;
u64 address = 0; u64 address = 0;
if (!m_cpu->evaluateExpression(targetString.toStdString().c_str(), address)) std::string error;
if (!m_cpu->evaluateExpression(targetString.toStdString().c_str(), address, error))
{ {
QMessageBox::warning(this, tr("Cannot Go To"), getExpressionError()); QMessageBox::warning(this, tr("Cannot Go To"), QString::fromStdString(error));
return; return;
} }

View File

@ -599,9 +599,10 @@ void MemoryViewWidget::contextGoToAddress()
return; return;
u64 address = 0; u64 address = 0;
if (!m_cpu->evaluateExpression(targetString.toStdString().c_str(), address)) std::string error;
if (!m_cpu->evaluateExpression(targetString.toStdString().c_str(), address, error))
{ {
QMessageBox::warning(this, tr("Cannot Go To"), getExpressionError()); QMessageBox::warning(this, tr("Cannot Go To"), QString::fromStdString(error));
return; return;
} }

View File

@ -273,6 +273,8 @@ Qt::ItemFlags BreakpointModel::flags(const QModelIndex& index) const
bool BreakpointModel::setData(const QModelIndex& index, const QVariant& value, int role) bool BreakpointModel::setData(const QModelIndex& index, const QVariant& value, int role)
{ {
std::string error;
if (role == Qt::CheckStateRole && index.column() == BreakpointColumns::ENABLED) if (role == Qt::CheckStateRole && index.column() == BreakpointColumns::ENABLED)
{ {
auto bp_mc = m_breakpoints.at(index.row()); auto bp_mc = m_breakpoints.at(index.row());
@ -314,9 +316,9 @@ bool BreakpointModel::setData(const QModelIndex& index, const QVariant& value, i
{ {
PostfixExpression expr; PostfixExpression expr;
if (!m_cpu.initExpression(condValue.toLocal8Bit().constData(), expr)) if (!m_cpu.initExpression(condValue.toLocal8Bit().constData(), expr, error))
{ {
QMessageBox::warning(nullptr, "Condition Error", QString(getExpressionError())); QMessageBox::warning(nullptr, "Condition Error", QString::fromStdString(error));
return false; return false;
} }
@ -347,9 +349,9 @@ bool BreakpointModel::setData(const QModelIndex& index, const QVariant& value, i
{ {
PostfixExpression expr; PostfixExpression expr;
if (!m_cpu.initExpression(condValue.toLocal8Bit().constData(), expr)) if (!m_cpu.initExpression(condValue.toLocal8Bit().constData(), expr, error))
{ {
QMessageBox::warning(nullptr, "Condition Error", QString(getExpressionError())); QMessageBox::warning(nullptr, "Condition Error", QString::fromStdString(error));
return false; return false;
} }
@ -456,17 +458,20 @@ void BreakpointModel::refreshData()
void BreakpointModel::loadBreakpointFromFieldList(QStringList fields) void BreakpointModel::loadBreakpointFromFieldList(QStringList fields)
{ {
std::string error;
bool ok; bool ok;
if (fields.size() != BreakpointModel::BreakpointColumns::COLUMN_COUNT) if (fields.size() != BreakpointColumns::COLUMN_COUNT)
{ {
Console.WriteLn("Debugger Breakpoint Model: Invalid number of columns, skipping"); Console.WriteLn("Debugger Breakpoint Model: Invalid number of columns, skipping");
return; return;
} }
const int type = fields[BreakpointModel::BreakpointColumns::TYPE].toUInt(&ok); const int type = fields[BreakpointColumns::TYPE].toUInt(&ok);
if (!ok) if (!ok)
{ {
Console.WriteLn("Debugger Breakpoint Model: Failed to parse type '%s', skipping", fields[BreakpointModel::BreakpointColumns::TYPE].toUtf8().constData()); Console.WriteLn("Debugger Breakpoint Model: Failed to parse type '%s', skipping",
fields[BreakpointColumns::TYPE].toUtf8().constData());
return; return;
} }
@ -476,34 +481,37 @@ void BreakpointModel::loadBreakpointFromFieldList(QStringList fields)
BreakPoint bp; BreakPoint bp;
// Address // Address
bp.addr = fields[BreakpointModel::BreakpointColumns::OFFSET].toUInt(&ok, 16); bp.addr = fields[BreakpointColumns::OFFSET].toUInt(&ok, 16);
if (!ok) if (!ok)
{ {
Console.WriteLn("Debugger Breakpoint Model: Failed to parse address '%s', skipping", fields[BreakpointModel::BreakpointColumns::OFFSET].toUtf8().constData()); Console.WriteLn("Debugger Breakpoint Model: Failed to parse address '%s', skipping",
fields[BreakpointColumns::OFFSET].toUtf8().constData());
return; return;
} }
// Condition // Condition
if (!fields[BreakpointModel::BreakpointColumns::CONDITION].isEmpty()) if (!fields[BreakpointColumns::CONDITION].isEmpty())
{ {
PostfixExpression expr; PostfixExpression expr;
bp.hasCond = true; bp.hasCond = true;
bp.cond.debug = &m_cpu; bp.cond.debug = &m_cpu;
if (!m_cpu.initExpression(fields[BreakpointModel::BreakpointColumns::CONDITION].toUtf8().constData(), expr)) if (!m_cpu.initExpression(fields[BreakpointColumns::CONDITION].toUtf8().constData(), expr, error))
{ {
Console.WriteLn("Debugger Breakpoint Model: Failed to parse cond '%s', skipping", fields[BreakpointModel::BreakpointColumns::CONDITION].toUtf8().constData()); Console.WriteLn("Debugger Breakpoint Model: Failed to parse cond '%s', skipping",
fields[BreakpointModel::CONDITION].toUtf8().constData());
return; return;
} }
bp.cond.expression = expr; bp.cond.expression = expr;
bp.cond.expressionString = fields[BreakpointModel::BreakpointColumns::CONDITION].toStdString(); bp.cond.expressionString = fields[BreakpointColumns::CONDITION].toStdString();
} }
// Enabled // Enabled
bp.enabled = fields[BreakpointModel::BreakpointColumns::ENABLED].toUInt(&ok); bp.enabled = fields[BreakpointColumns::ENABLED].toUInt(&ok);
if (!ok) if (!ok)
{ {
Console.WriteLn("Debugger Breakpoint Model: Failed to parse enable flag '%s', skipping", fields[BreakpointModel::BreakpointColumns::ENABLED].toUtf8().constData()); Console.WriteLn("Debugger Breakpoint Model: Failed to parse enable flag '%s', skipping",
fields[BreakpointColumns::ENABLED].toUtf8().constData());
return; return;
} }
@ -515,49 +523,54 @@ void BreakpointModel::loadBreakpointFromFieldList(QStringList fields)
// Mode // Mode
if (type >= MEMCHECK_INVALID) if (type >= MEMCHECK_INVALID)
{ {
Console.WriteLn("Debugger Breakpoint Model: Failed to parse cond type '%s', skipping", fields[BreakpointModel::BreakpointColumns::TYPE].toUtf8().constData()); Console.WriteLn("Debugger Breakpoint Model: Failed to parse cond type '%s', skipping",
fields[BreakpointColumns::TYPE].toUtf8().constData());
return; return;
} }
mc.memCond = static_cast<MemCheckCondition>(type); mc.memCond = static_cast<MemCheckCondition>(type);
// Address // Address
QString test = fields[BreakpointModel::BreakpointColumns::OFFSET]; QString test = fields[BreakpointColumns::OFFSET];
mc.start = fields[BreakpointModel::BreakpointColumns::OFFSET].toUInt(&ok, 16); mc.start = fields[BreakpointColumns::OFFSET].toUInt(&ok, 16);
if (!ok) if (!ok)
{ {
Console.WriteLn("Debugger Breakpoint Model: Failed to parse address '%s', skipping", fields[BreakpointModel::BreakpointColumns::OFFSET].toUtf8().constData()); Console.WriteLn("Debugger Breakpoint Model: Failed to parse address '%s', skipping",
fields[BreakpointColumns::OFFSET].toUtf8().constData());
return; return;
} }
// Size // Size
mc.end = fields[BreakpointModel::BreakpointColumns::SIZE_LABEL].toUInt(&ok) + mc.start; mc.end = fields[BreakpointColumns::SIZE_LABEL].toUInt(&ok) + mc.start;
if (!ok) if (!ok)
{ {
Console.WriteLn("Debugger Breakpoint Model: Failed to parse length '%s', skipping", fields[BreakpointModel::BreakpointColumns::SIZE_LABEL].toUtf8().constData()); Console.WriteLn("Debugger Breakpoint Model: Failed to parse length '%s', skipping",
fields[BreakpointColumns::SIZE_LABEL].toUtf8().constData());
return; return;
} }
// Condition // Condition
if (!fields[BreakpointModel::BreakpointColumns::CONDITION].isEmpty()) if (!fields[BreakpointColumns::CONDITION].isEmpty())
{ {
PostfixExpression expr; PostfixExpression expr;
mc.hasCond = true; mc.hasCond = true;
mc.cond.debug = &m_cpu; mc.cond.debug = &m_cpu;
if (!m_cpu.initExpression(fields[BreakpointModel::BreakpointColumns::CONDITION].toUtf8().constData(), expr)) if (!m_cpu.initExpression(fields[BreakpointColumns::CONDITION].toUtf8().constData(), expr, error))
{ {
Console.WriteLn("Debugger Breakpoint Model: Failed to parse cond '%s', skipping", fields[BreakpointModel::BreakpointColumns::CONDITION].toUtf8().constData()); Console.WriteLn("Debugger Breakpoint Model: Failed to parse cond '%s', skipping",
fields[BreakpointColumns::CONDITION].toUtf8().constData());
return; return;
} }
mc.cond.expression = expr; mc.cond.expression = expr;
mc.cond.expressionString = fields[BreakpointModel::BreakpointColumns::CONDITION].toStdString(); mc.cond.expressionString = fields[BreakpointColumns::CONDITION].toStdString();
} }
// Result // Result
const int result = fields[BreakpointModel::BreakpointColumns::ENABLED].toUInt(&ok); const int result = fields[BreakpointColumns::ENABLED].toUInt(&ok);
if (!ok) if (!ok)
{ {
Console.WriteLn("Debugger Breakpoint Model: Failed to parse result flag '%s', skipping", fields[BreakpointModel::BreakpointColumns::ENABLED].toUtf8().constData()); Console.WriteLn("Debugger Breakpoint Model: Failed to parse result flag '%s', skipping",
fields[BreakpointColumns::ENABLED].toUtf8().constData());
return; return;
} }
mc.result = static_cast<MemCheckResult>(result); mc.result = static_cast<MemCheckResult>(result);

View File

@ -24,7 +24,8 @@ struct BreakPointCond
u32 Evaluate() u32 Evaluate()
{ {
u64 result; u64 result;
if (!debug->parseExpression(expression, result) || result == 0) std::string error;
if (!debug->parseExpression(expression, result, error) || result == 0)
return 0; return 0;
return 1; return 1;
} }

View File

@ -340,7 +340,7 @@ std::optional<u32> DebugInterface::getStackFrameSize(const ccc::Function& functi
// The stack frame size isn't stored in the symbol table, so we try // The stack frame size isn't stored in the symbol table, so we try
// to extract it from the code by checking for an instruction at the // to extract it from the code by checking for an instruction at the
// start of the current function that is in the form of // start of the current function that is in the form of
// "addui $sp, $sp, frame_size" instead. // "addiu $sp, $sp, frame_size" instead.
u32 instruction = read32(function.address().value); u32 instruction = read32(function.address().value);
@ -354,29 +354,29 @@ std::optional<u32> DebugInterface::getStackFrameSize(const ccc::Function& functi
return static_cast<u32>(stack_frame_size); return static_cast<u32>(stack_frame_size);
} }
bool DebugInterface::evaluateExpression(const char* expression, u64& dest) bool DebugInterface::evaluateExpression(const char* expression, u64& dest, std::string& error)
{ {
PostfixExpression postfix; PostfixExpression postfix;
if (!initExpression(expression, postfix)) if (!initExpression(expression, postfix, error))
return false; return false;
if (!parseExpression(postfix, dest)) if (!parseExpression(postfix, dest, error))
return false; return false;
return true; return true;
} }
bool DebugInterface::initExpression(const char* exp, PostfixExpression& dest) bool DebugInterface::initExpression(const char* exp, PostfixExpression& dest, std::string& error)
{ {
MipsExpressionFunctions funcs(this, true); MipsExpressionFunctions funcs(this, true);
return initPostfixExpression(exp, &funcs, dest); return initPostfixExpression(exp, &funcs, dest, error);
} }
bool DebugInterface::parseExpression(PostfixExpression& exp, u64& dest) bool DebugInterface::parseExpression(PostfixExpression& exp, u64& dest, std::string& error)
{ {
MipsExpressionFunctions funcs(this, false); MipsExpressionFunctions funcs(this, false);
return parsePostfixExpression(exp, &funcs, dest); return parsePostfixExpression(exp, &funcs, dest, error);
} }
// //
@ -904,12 +904,10 @@ std::vector<std::unique_ptr<BiosThread>> R5900DebugInterface::GetThreadList() co
return getEEThreads(); return getEEThreads();
} }
// //
// R3000DebugInterface // R3000DebugInterface
// //
BreakPointCpu R3000DebugInterface::getCpuType() BreakPointCpu R3000DebugInterface::getCpuType()
{ {
return BREAKPOINT_IOP; return BREAKPOINT_IOP;

View File

@ -86,9 +86,9 @@ public:
virtual SymbolImporter* GetSymbolImporter() const = 0; virtual SymbolImporter* GetSymbolImporter() const = 0;
virtual std::vector<std::unique_ptr<BiosThread>> GetThreadList() const = 0; virtual std::vector<std::unique_ptr<BiosThread>> GetThreadList() const = 0;
bool evaluateExpression(const char* expression, u64& dest); bool evaluateExpression(const char* expression, u64& dest, std::string& error);
bool initExpression(const char* exp, PostfixExpression& dest); bool initExpression(const char* exp, PostfixExpression& dest, std::string& error);
bool parseExpression(PostfixExpression& exp, u64& dest); bool parseExpression(PostfixExpression& exp, u64& dest, std::string& error);
bool isAlive(); bool isAlive();
bool isCpuPaused(); bool isCpuPaused();
void pauseCpu(); void pauseCpu();

View File

@ -21,8 +21,6 @@ typedef enum {
typedef enum { EXCOMM_CONST, EXCOMM_CONST_FLOAT, EXCOMM_REF, EXCOMM_OP } ExpressionCommand; typedef enum { EXCOMM_CONST, EXCOMM_CONST_FLOAT, EXCOMM_REF, EXCOMM_OP } ExpressionCommand;
static std::string expressionError;
typedef struct { typedef struct {
char Name[4]; char Name[4];
unsigned char Priority; unsigned char Priority;
@ -209,10 +207,8 @@ bool isAlphaNum(char c)
c == '@' || c == '_' || c == '$' || c == '.'); c == '@' || c == '_' || c == '$' || c == '.');
} }
bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, PostfixExpression& dest) bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, PostfixExpression& dest, std::string& error)
{ {
expressionError.clear();
int infixPos = 0; int infixPos = 0;
int infixLen = (int)strlen(infix); int infixLen = (int)strlen(infix);
ExpressionOpcodeType lastOpcode = EXOP_NONE; ExpressionOpcodeType lastOpcode = EXOP_NONE;
@ -241,7 +237,7 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
if(subPos == sizeof(subStr) - 1) if(subPos == sizeof(subStr) - 1)
{ {
expressionError = TRANSLATE("ExpressionParser", "Token too long."); error = TRANSLATE("ExpressionParser", "Token too long.");
return false; return false;
} }
@ -251,7 +247,7 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
isFloat = true; isFloat = true;
else if (!parseNumber(subStr,16,subPos,value)) else if (!parseNumber(subStr,16,subPos,value))
{ {
expressionError = StringUtil::StdStringFromFormat( error = StringUtil::StdStringFromFormat(
TRANSLATE("ExpressionParser", "Invalid number \"%s\"."), subStr); TRANSLATE("ExpressionParser", "Invalid number \"%s\"."), subStr);
return false; return false;
} }
@ -268,7 +264,7 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
if(subPos == sizeof(subStr) - 1) if(subPos == sizeof(subStr) - 1)
{ {
expressionError = TRANSLATE("ExpressionParser", "Token too long."); error = TRANSLATE("ExpressionParser", "Token too long.");
return false; return false;
} }
@ -294,7 +290,7 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
continue; continue;
} }
expressionError = StringUtil::StdStringFromFormat( error = StringUtil::StdStringFromFormat(
TRANSLATE("ExpressionParser", "Invalid symbol \"%s\"."), subStr); TRANSLATE("ExpressionParser", "Invalid symbol \"%s\"."), subStr);
return false; return false;
} else { } else {
@ -302,7 +298,7 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
ExpressionOpcodeType type = getExpressionOpcode(&infix[infixPos],len,lastOpcode); ExpressionOpcodeType type = getExpressionOpcode(&infix[infixPos],len,lastOpcode);
if (type == EXOP_NONE) if (type == EXOP_NONE)
{ {
expressionError = StringUtil::StdStringFromFormat( error = StringUtil::StdStringFromFormat(
TRANSLATE("ExpressionParser", "Invalid operator at \"%s\"."), &infix[infixPos]); TRANSLATE("ExpressionParser", "Invalid operator at \"%s\"."), &infix[infixPos]);
return false; return false;
} }
@ -318,7 +314,7 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
{ {
if (opcodeStack.empty()) if (opcodeStack.empty())
{ {
expressionError = TRANSLATE("ExpressionParser", "Closing parenthesis without opening one."); error = TRANSLATE("ExpressionParser", "Closing parenthesis without opening one.");
return false; return false;
} }
ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1]; ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1];
@ -332,7 +328,7 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
{ {
if (opcodeStack.empty()) if (opcodeStack.empty())
{ {
expressionError = TRANSLATE("ExpressionParser", "Closing bracket without opening one."); error = TRANSLATE("ExpressionParser", "Closing bracket without opening one.");
return false; return false;
} }
ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1]; ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1];
@ -385,7 +381,7 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
if (t == EXOP_BRACKETL) // opening bracket without closing one if (t == EXOP_BRACKETL) // opening bracket without closing one
{ {
expressionError = TRANSLATE("ExpressionParser", "Parenthesis not closed."); error = TRANSLATE("ExpressionParser", "Parenthesis not closed.");
return false; return false;
} }
dest.push_back(ExpressionPair(EXCOMM_OP,t)); dest.push_back(ExpressionPair(EXCOMM_OP,t));
@ -415,7 +411,7 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
return true; return true;
} }
bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs, u64& dest) bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs, u64& dest, std::string& error)
{ {
size_t num = 0; size_t num = 0;
u64 opcode; u64 opcode;
@ -444,7 +440,7 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs,
opcode = exp[num++].second; opcode = exp[num++].second;
if (valueStack.size() < ExpressionOpcodes[opcode].args) if (valueStack.size() < ExpressionOpcodes[opcode].args)
{ {
expressionError = TRANSLATE("ExpressionParser", "Not enough arguments."); error = TRANSLATE("ExpressionParser", "Not enough arguments.");
return false; return false;
} }
for (int l = 0; l < ExpressionOpcodes[opcode].args; l++) for (int l = 0; l < ExpressionOpcodes[opcode].args; l++)
@ -459,12 +455,12 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs,
case EXOP_MEMSIZE: // must be followed by EXOP_MEM case EXOP_MEMSIZE: // must be followed by EXOP_MEM
if (exp[num++].second != EXOP_MEM) if (exp[num++].second != EXOP_MEM)
{ {
expressionError = TRANSLATE("ExpressionParser", "Invalid memsize operator."); error = TRANSLATE("ExpressionParser", "Invalid memsize operator.");
return false; return false;
} }
u64 val; u64 val;
if(!funcs->getMemoryValue(arg[1],arg[0],val,expressionError)) if(!funcs->getMemoryValue(arg[1],arg[0],val,error))
{ {
return false; return false;
} }
@ -473,7 +469,7 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs,
case EXOP_MEM: case EXOP_MEM:
{ {
u64 val; u64 val;
if (!funcs->getMemoryValue(arg[0],4,val,expressionError)) if (!funcs->getMemoryValue(arg[0],4,val,error))
{ {
return false; return false;
} }
@ -503,7 +499,7 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs,
case EXOP_DIV: // a/b case EXOP_DIV: // a/b
if (arg[0] == 0) if (arg[0] == 0)
{ {
expressionError = TRANSLATE("ExpressionParser", "Division by zero."); error = TRANSLATE("ExpressionParser", "Division by zero.");
return false; return false;
} }
if (useFloat) if (useFloat)
@ -514,7 +510,7 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs,
case EXOP_MOD: // a%b case EXOP_MOD: // a%b
if (arg[0] == 0) if (arg[0] == 0)
{ {
expressionError = TRANSLATE("ExpressionParser", "Modulo by zero."); error = TRANSLATE("ExpressionParser", "Modulo by zero.");
return false; return false;
} }
valueStack.push_back(arg[1]%arg[0]); valueStack.push_back(arg[1]%arg[0]);
@ -593,7 +589,7 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs,
case EXOP_TERTELSE: // exp ? exp : exp, else muss zuerst kommen! case EXOP_TERTELSE: // exp ? exp : exp, else muss zuerst kommen!
if (exp[num++].second != EXOP_TERTIF) if (exp[num++].second != EXOP_TERTIF)
{ {
expressionError = TRANSLATE("ExpressionParser", "Invalid tertiary operator."); error = TRANSLATE("ExpressionParser", "Invalid tertiary operator.");
return false; return false;
} }
valueStack.push_back(arg[2]?arg[1]:arg[0]); valueStack.push_back(arg[2]?arg[1]:arg[0]);
@ -608,17 +604,9 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs,
return true; return true;
} }
bool parseExpression(char* exp, IExpressionFunctions* funcs, u64& dest) bool parseExpression(const char* exp, IExpressionFunctions* funcs, u64& dest, std::string& error)
{ {
PostfixExpression postfix; PostfixExpression postfix;
if (!initPostfixExpression(exp,funcs,postfix)) return false; if (!initPostfixExpression(exp,funcs,postfix,error)) return false;
return parsePostfixExpression(postfix,funcs,dest); return parsePostfixExpression(postfix,funcs,dest,error);
}
const char* getExpressionError()
{
if (expressionError.empty())
return TRANSLATE("ExpressionParser", "Invalid expression.");
return expressionError.c_str();
} }

View File

@ -26,7 +26,6 @@ public:
virtual bool getMemoryValue(u32 address, int size, u64& dest, std::string& error) = 0; virtual bool getMemoryValue(u32 address, int size, u64& dest, std::string& error) = 0;
}; };
bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, PostfixExpression& dest); bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, PostfixExpression& dest, std::string& error);
bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs, u64& dest); bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs, u64& dest, std::string& error);
bool parseExpression(const char* exp, IExpressionFunctions* funcs, u64& dest); bool parseExpression(const char* exp, IExpressionFunctions* funcs, u64& dest, std::string& error);
const char* getExpressionError();

View File

@ -355,11 +355,12 @@ bool MipsCheckImmediate(const char* Source, DebugInterface* cpu, int& dest, int&
RetLen = SourceLen; RetLen = SourceLen;
PostfixExpression postfix; PostfixExpression postfix;
if (!cpu->initExpression(Buffer,postfix)) std::string error;
if (!cpu->initExpression(Buffer,postfix,error))
return false; return false;
u64 value; u64 value;
if (!cpu->parseExpression(postfix,value)) if (!cpu->parseExpression(postfix,value,error))
return false; return false;
dest = (int) value; dest = (int) value;