Debugger: Bring back the expression parser

This commit is contained in:
chaoticgd 2024-09-01 19:13:14 +01:00 committed by Ty
parent f340b5ebd0
commit 90463a4a6c
10 changed files with 183 additions and 81 deletions

View File

@ -93,10 +93,9 @@ void BreakpointDialog::accept()
PostfixExpression expr; PostfixExpression expr;
u64 address; u64 address;
if (!m_cpu->initExpression(m_ui.txtAddress->text().toLocal8Bit().constData(), expr) || if (!m_cpu->evaluateExpression(m_ui.txtAddress->text().toStdString().c_str(), address))
!m_cpu->parseExpression(expr, address))
{ {
QMessageBox::warning(this, tr("Error"), tr("Invalid address \"%1\"").arg(m_ui.txtAddress->text())); QMessageBox::warning(this, tr("Invalid Address"), getExpressionError());
return; return;
} }
@ -109,9 +108,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().toLocal8Bit().constData(), expr)) if (!m_cpu->initExpression(m_ui.txtCondition->text().toStdString().c_str(), expr))
{ {
QMessageBox::warning(this, tr("Error"), tr("Invalid condition \"%1\"").arg(getExpressionError())); QMessageBox::warning(this, tr("Invalid Condition"), getExpressionError());
return; return;
} }
@ -121,21 +120,17 @@ void BreakpointDialog::accept()
} }
if (auto* mc = std::get_if<MemCheck>(&m_bp_mc)) if (auto* mc = std::get_if<MemCheck>(&m_bp_mc))
{ {
PostfixExpression expr;
u64 startAddress; u64 startAddress;
if (!m_cpu->initExpression(m_ui.txtAddress->text().toLocal8Bit().constData(), expr) || if (!m_cpu->evaluateExpression(m_ui.txtAddress->text().toStdString().c_str(), startAddress))
!m_cpu->parseExpression(expr, startAddress))
{ {
QMessageBox::warning(this, tr("Error"), tr("Invalid address \"%1\"").arg(m_ui.txtAddress->text())); QMessageBox::warning(this, tr("Invalid Address"), getExpressionError());
return; return;
} }
u64 size; u64 size;
if (!m_cpu->initExpression(m_ui.txtSize->text().toLocal8Bit(), expr) || if (!m_cpu->evaluateExpression(m_ui.txtSize->text().toStdString().c_str(), size) || !size)
!m_cpu->parseExpression(expr, size) || !size)
{ {
QMessageBox::warning(this, tr("Error"), tr("Invalid size \"%1\"").arg(m_ui.txtSize->text())); QMessageBox::warning(this, tr("Invalid Size"), getExpressionError());
return; return;
} }
@ -147,9 +142,10 @@ void BreakpointDialog::accept()
mc->hasCond = true; mc->hasCond = true;
mc->cond.debug = m_cpu; mc->cond.debug = m_cpu;
if (!m_cpu->initExpression(m_ui.txtCondition->text().toLocal8Bit().constData(), expr)) PostfixExpression expr;
if (!m_cpu->initExpression(m_ui.txtCondition->text().toStdString().c_str(), expr))
{ {
QMessageBox::warning(this, tr("Error"), tr("Invalid condition \"%1\"").arg(getExpressionError())); QMessageBox::warning(this, tr("Invalid Condition"), getExpressionError());
return; return;
} }

View File

@ -163,21 +163,20 @@ void DisassemblyWidget::contextFollowBranch()
void DisassemblyWidget::contextGoToAddress() void DisassemblyWidget::contextGoToAddress()
{ {
bool ok; bool ok;
const QString targetString = QInputDialog::getText(this, tr("Go to address"), "", const QString targetString = QInputDialog::getText(this, tr("Go To In Disassembly"), "",
QLineEdit::Normal, "", &ok); QLineEdit::Normal, "", &ok);
if (!ok) if (!ok)
return; return;
const u32 targetAddress = targetString.toUInt(&ok, 16) & ~3; u64 address = 0;
if (!m_cpu->evaluateExpression(targetString.toStdString().c_str(), address))
if (!ok)
{ {
QMessageBox::warning(this, tr("Go to address error"), tr("Invalid address")); QMessageBox::warning(this, tr("Cannot Go To"), getExpressionError());
return; return;
} }
gotoAddressAndSetFocus(targetAddress); gotoAddressAndSetFocus(static_cast<u32>(address) & ~3);
} }
void DisassemblyWidget::contextAddFunction() void DisassemblyWidget::contextAddFunction()

View File

@ -592,21 +592,20 @@ void MemoryViewWidget::contextPaste()
void MemoryViewWidget::contextGoToAddress() void MemoryViewWidget::contextGoToAddress()
{ {
bool ok; bool ok;
QString targetString = QInputDialog::getText(this, tr("Go to address"), "", QString targetString = QInputDialog::getText(this, tr("Go To In Memory View"), "",
QLineEdit::Normal, "", &ok); QLineEdit::Normal, "", &ok);
if (!ok) if (!ok)
return; return;
const u32 targetAddress = targetString.toUInt(&ok, 16); u64 address = 0;
if (!m_cpu->evaluateExpression(targetString.toStdString().c_str(), address))
if (!ok)
{ {
QMessageBox::warning(this, "Go to address error", "Invalid address"); QMessageBox::warning(this, tr("Cannot Go To"), getExpressionError());
return; return;
} }
gotoAddress(targetAddress); gotoAddress(static_cast<u32>(address));
} }
void MemoryViewWidget::mouseDoubleClickEvent(QMouseEvent* event) void MemoryViewWidget::mouseDoubleClickEvent(QMouseEvent* event)

View File

@ -25,6 +25,7 @@ public:
Tag tag = OBJECT; Tag tag = OBJECT;
ccc::MultiSymbolHandle symbol; ccc::MultiSymbolHandle symbol;
QString name; QString name;
QString mangled_name;
SymbolTreeLocation location; SymbolTreeLocation location;
bool is_location_editable = false; bool is_location_editable = false;
std::optional<u32> size; std::optional<u32> size;

View File

@ -362,6 +362,13 @@ void SymbolTreeWidget::setupMenu()
connect(copy_name, &QAction::triggered, this, &SymbolTreeWidget::onCopyName); connect(copy_name, &QAction::triggered, this, &SymbolTreeWidget::onCopyName);
m_context_menu->addAction(copy_name); m_context_menu->addAction(copy_name);
if (m_flags & ALLOW_MANGLED_NAME_ACTIONS)
{
QAction* copy_mangled_name = new QAction(tr("Copy Mangled Name"), this);
connect(copy_mangled_name, &QAction::triggered, this, &SymbolTreeWidget::onCopyMangledName);
m_context_menu->addAction(copy_mangled_name);
}
QAction* copy_location = new QAction(tr("Copy Location"), this); QAction* copy_location = new QAction(tr("Copy Location"), this);
connect(copy_location, &QAction::triggered, this, &SymbolTreeWidget::onCopyLocation); connect(copy_location, &QAction::triggered, this, &SymbolTreeWidget::onCopyLocation);
m_context_menu->addAction(copy_location); m_context_menu->addAction(copy_location);
@ -484,6 +491,18 @@ void SymbolTreeWidget::onCopyName()
QApplication::clipboard()->setText(node->name); QApplication::clipboard()->setText(node->name);
} }
void SymbolTreeWidget::onCopyMangledName()
{
SymbolTreeNode* node = currentNode();
if (!node)
return;
if (!node->mangled_name.isEmpty())
QApplication::clipboard()->setText(node->mangled_name);
else
QApplication::clipboard()->setText(node->name);
}
void SymbolTreeWidget::onCopyLocation() void SymbolTreeWidget::onCopyLocation()
{ {
SymbolTreeNode* node = currentNode(); SymbolTreeNode* node = currentNode();
@ -611,7 +630,7 @@ SymbolTreeNode* SymbolTreeWidget::currentNode()
// ***************************************************************************** // *****************************************************************************
FunctionTreeWidget::FunctionTreeWidget(DebugInterface& cpu, QWidget* parent) FunctionTreeWidget::FunctionTreeWidget(DebugInterface& cpu, QWidget* parent)
: SymbolTreeWidget(ALLOW_GROUPING, 4, cpu, parent) : SymbolTreeWidget(ALLOW_GROUPING | ALLOW_MANGLED_NAME_ACTIONS, 4, cpu, parent)
{ {
} }
@ -652,6 +671,7 @@ std::unique_ptr<SymbolTreeNode> FunctionTreeWidget::buildNode(
std::unique_ptr<SymbolTreeNode> node = std::make_unique<SymbolTreeNode>(); std::unique_ptr<SymbolTreeNode> node = std::make_unique<SymbolTreeNode>();
node->name = std::move(work.name); node->name = std::move(work.name);
node->mangled_name = QString::fromStdString(function.mangled_name());
node->location = SymbolTreeLocation(SymbolTreeLocation::MEMORY, function.address().value); node->location = SymbolTreeLocation(SymbolTreeLocation::MEMORY, function.address().value);
node->size = function.size(); node->size = function.size();
node->symbol = ccc::MultiSymbolHandle(function); node->symbol = ccc::MultiSymbolHandle(function);
@ -694,7 +714,7 @@ void FunctionTreeWidget::onNewButtonPressed()
// ***************************************************************************** // *****************************************************************************
GlobalVariableTreeWidget::GlobalVariableTreeWidget(DebugInterface& cpu, QWidget* parent) GlobalVariableTreeWidget::GlobalVariableTreeWidget(DebugInterface& cpu, QWidget* parent)
: SymbolTreeWidget(ALLOW_GROUPING | ALLOW_SORTING_BY_IF_TYPE_IS_KNOWN | ALLOW_TYPE_ACTIONS, 1, cpu, parent) : SymbolTreeWidget(ALLOW_GROUPING | ALLOW_SORTING_BY_IF_TYPE_IS_KNOWN | ALLOW_TYPE_ACTIONS | ALLOW_MANGLED_NAME_ACTIONS, 1, cpu, parent)
{ {
} }
@ -777,6 +797,7 @@ std::unique_ptr<SymbolTreeNode> GlobalVariableTreeWidget::buildNode(
{ {
const ccc::GlobalVariable& global_variable = static_cast<const ccc::GlobalVariable&>(*work.symbol); const ccc::GlobalVariable& global_variable = static_cast<const ccc::GlobalVariable&>(*work.symbol);
node->mangled_name = QString::fromStdString(global_variable.mangled_name());
if (global_variable.type()) if (global_variable.type())
node->type = ccc::NodeHandle(global_variable, global_variable.type()); node->type = ccc::NodeHandle(global_variable, global_variable.type());
node->location = SymbolTreeLocation(SymbolTreeLocation::MEMORY, global_variable.address().value); node->location = SymbolTreeLocation(SymbolTreeLocation::MEMORY, global_variable.address().value);

View File

@ -84,6 +84,7 @@ protected:
void onDeleteButtonPressed(); void onDeleteButtonPressed();
void onCopyName(); void onCopyName();
void onCopyMangledName();
void onCopyLocation(); void onCopyLocation();
void onRenameSymbol(); void onRenameSymbol();
void onGoToInDisassembly(); void onGoToInDisassembly();
@ -117,7 +118,8 @@ protected:
NO_SYMBOL_TREE_FLAGS = 0, NO_SYMBOL_TREE_FLAGS = 0,
ALLOW_GROUPING = 1 << 0, ALLOW_GROUPING = 1 << 0,
ALLOW_SORTING_BY_IF_TYPE_IS_KNOWN = 1 << 1, ALLOW_SORTING_BY_IF_TYPE_IS_KNOWN = 1 << 1,
ALLOW_TYPE_ACTIONS = 1 << 2 ALLOW_TYPE_ACTIONS = 1 << 2,
ALLOW_MANGLED_NAME_ACTIONS = 1 << 3
}; };
u32 m_flags; u32 m_flags;

View File

@ -10,17 +10,13 @@
#include "GS.h" // Required for gsNonMirroredRead() #include "GS.h" // Required for gsNonMirroredRead()
#include "Counters.h" #include "Counters.h"
#include "Host.h"
#include "R3000A.h" #include "R3000A.h"
#include "IopMem.h" #include "IopMem.h"
#include "VMManager.h" #include "VMManager.h"
#include "common/StringUtil.h" #include "common/StringUtil.h"
#ifdef __clang__
// TODO: The sprintf() usage here needs to be rewritten...
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
R5900DebugInterface r5900Debug; R5900DebugInterface r5900Debug;
R3000DebugInterface r3000Debug; R3000DebugInterface r3000Debug;
@ -45,8 +41,20 @@ enum ReferenceIndexType
class MipsExpressionFunctions : public IExpressionFunctions class MipsExpressionFunctions : public IExpressionFunctions
{ {
public: public:
explicit MipsExpressionFunctions(DebugInterface* cpu) explicit MipsExpressionFunctions(DebugInterface* cpu, bool enumerateSymbols)
: cpu(cpu){}; : m_cpu(cpu)
{
if (!enumerateSymbols)
return;
m_cpu->GetSymbolGuardian().Read([&](const ccc::SymbolDatabase& database) {
for (const ccc::Function& function : database.functions)
m_mangled_function_names_to_handles.emplace(function.mangled_name(), function.handle());
for (const ccc::GlobalVariable& global : database.global_variables)
m_mangled_global_names_to_handles.emplace(global.mangled_name(), global.handle());
});
}
virtual bool parseReference(char* str, u64& referenceIndex) virtual bool parseReference(char* str, u64& referenceIndex)
{ {
@ -54,7 +62,7 @@ public:
{ {
char reg[8]; char reg[8];
std::snprintf(reg, std::size(reg), "r%d", i); std::snprintf(reg, std::size(reg), "r%d", i);
if (StringUtil::Strcasecmp(str, reg) == 0 || StringUtil::Strcasecmp(str, cpu->getRegisterName(0, i)) == 0) if (StringUtil::Strcasecmp(str, reg) == 0 || StringUtil::Strcasecmp(str, m_cpu->getRegisterName(0, i)) == 0)
{ {
referenceIndex = i; referenceIndex = i;
return true; return true;
@ -108,27 +116,62 @@ public:
virtual bool parseSymbol(char* str, u64& symbolValue) virtual bool parseSymbol(char* str, u64& symbolValue)
{ {
SymbolInfo symbol = cpu->GetSymbolGuardian().SymbolWithName(std::string(str)); bool success = false;
if (!symbol.address.valid()) m_cpu->GetSymbolGuardian().Read([&](const ccc::SymbolDatabase& database) {
return false; std::string name = str;
symbolValue = symbol.address.value; // Check for mangled function names.
return true; auto function_iterator = m_mangled_function_names_to_handles.find(name);
if (function_iterator != m_mangled_function_names_to_handles.end())
{
const ccc::Function* function = database.functions.symbol_from_handle(function_iterator->second);
if (function && function->address().valid())
{
symbolValue = function->address().value;
success = true;
return;
}
}
// Check for mangled global variable names.
auto global_iterator = m_mangled_global_names_to_handles.find(name);
if (global_iterator != m_mangled_global_names_to_handles.end())
{
const ccc::GlobalVariable* global = database.global_variables.symbol_from_handle(global_iterator->second);
if (global && global->address().valid())
{
symbolValue = global->address().value;
success = true;
return;
}
}
// Check for regular unmangled names.
const ccc::Symbol* symbol = database.symbol_with_name(name);
if (symbol && symbol->address().valid())
{
symbolValue = symbol->address().value;
success = true;
return;
}
});
return success;
} }
virtual u64 getReferenceValue(u64 referenceIndex) virtual u64 getReferenceValue(u64 referenceIndex)
{ {
if (referenceIndex < 32) if (referenceIndex < 32)
return cpu->getRegister(0, referenceIndex)._u64[0]; return m_cpu->getRegister(0, referenceIndex)._u64[0];
if (referenceIndex == REF_INDEX_PC) if (referenceIndex == REF_INDEX_PC)
return cpu->getPC(); return m_cpu->getPC();
if (referenceIndex == REF_INDEX_HI) if (referenceIndex == REF_INDEX_HI)
return cpu->getHI()._u64[0]; return m_cpu->getHI()._u64[0];
if (referenceIndex == REF_INDEX_LO) if (referenceIndex == REF_INDEX_LO)
return cpu->getLO()._u64[0]; return m_cpu->getLO()._u64[0];
if (referenceIndex & REF_INDEX_IS_OPSL) if (referenceIndex & REF_INDEX_IS_OPSL)
{ {
const u32 OP = memRead32(cpu->getPC()); const u32 OP = memRead32(m_cpu->getPC());
const R5900::OPCODE& opcode = R5900::GetInstruction(OP); const R5900::OPCODE& opcode = R5900::GetInstruction(OP);
if (opcode.flags & IS_MEMORY) if (opcode.flags & IS_MEMORY)
{ {
@ -154,7 +197,7 @@ public:
} }
if (referenceIndex & REF_INDEX_FPU) if (referenceIndex & REF_INDEX_FPU)
{ {
return cpu->getRegister(EECAT_FPR, referenceIndex & 0x1F)._u64[0]; return m_cpu->getRegister(EECAT_FPR, referenceIndex & 0x1F)._u64[0];
} }
return -1; return -1;
} }
@ -168,7 +211,7 @@ public:
return EXPR_TYPE_UINT; return EXPR_TYPE_UINT;
} }
virtual bool getMemoryValue(u32 address, int size, u64& dest, char* error) virtual bool getMemoryValue(u32 address, int size, u64& dest, std::string& error)
{ {
switch (size) switch (size)
{ {
@ -178,37 +221,40 @@ public:
case 8: case 8:
break; break;
default: default:
sprintf(error, "Invalid memory access size %d", size); error = StringUtil::StdStringFromFormat(
TRANSLATE("ExpressionParser", "Invalid memory access size %d."), size);
return false; return false;
} }
if (address % size) if (address % size)
{ {
sprintf(error, "Invalid memory access (unaligned)"); error = TRANSLATE("ExpressionParser", "Invalid memory access (unaligned).");
return false; return false;
} }
switch (size) switch (size)
{ {
case 1: case 1:
dest = cpu->read8(address); dest = m_cpu->read8(address);
break; break;
case 2: case 2:
dest = cpu->read16(address); dest = m_cpu->read16(address);
break; break;
case 4: case 4:
dest = cpu->read32(address); dest = m_cpu->read32(address);
break; break;
case 8: case 8:
dest = cpu->read64(address); dest = m_cpu->read64(address);
break; break;
} }
return true; return true;
} }
private: protected:
DebugInterface* cpu; DebugInterface* m_cpu;
std::map<std::string, ccc::FunctionHandle> m_mangled_function_names_to_handles;
std::map<std::string, ccc::GlobalVariableHandle> m_mangled_global_names_to_handles;
}; };
// //
@ -308,19 +354,31 @@ 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)
{
PostfixExpression postfix;
if (!initExpression(expression, postfix))
return false;
if (!parseExpression(postfix, dest))
return false;
return true;
}
bool DebugInterface::initExpression(const char* exp, PostfixExpression& dest) bool DebugInterface::initExpression(const char* exp, PostfixExpression& dest)
{ {
MipsExpressionFunctions funcs(this); MipsExpressionFunctions funcs(this, true);
return initPostfixExpression(exp, &funcs, dest); return initPostfixExpression(exp, &funcs, dest);
} }
bool DebugInterface::parseExpression(PostfixExpression& exp, u64& dest) bool DebugInterface::parseExpression(PostfixExpression& exp, u64& dest)
{ {
MipsExpressionFunctions funcs(this); MipsExpressionFunctions funcs(this, false);
return parsePostfixExpression(exp, &funcs, dest); return parsePostfixExpression(exp, &funcs, dest);
} }
// //
// R5900DebugInterface // R5900DebugInterface
// //

View File

@ -79,6 +79,7 @@ public:
[[nodiscard]] virtual SymbolGuardian& GetSymbolGuardian() const = 0; [[nodiscard]] virtual SymbolGuardian& GetSymbolGuardian() const = 0;
[[nodiscard]] virtual std::vector<std::unique_ptr<BiosThread>> GetThreadList() const = 0; [[nodiscard]] virtual std::vector<std::unique_ptr<BiosThread>> GetThreadList() const = 0;
bool evaluateExpression(const char* expression, u64& dest);
bool initExpression(const char* exp, PostfixExpression& dest); bool initExpression(const char* exp, PostfixExpression& dest);
bool parseExpression(PostfixExpression& exp, u64& dest); bool parseExpression(PostfixExpression& exp, u64& dest);
bool isAlive(); bool isAlive();

View File

@ -3,6 +3,9 @@
#include "ExpressionParser.h" #include "ExpressionParser.h"
#include "Host.h"
#include "common/StringUtil.h"
#include <cctype> #include <cctype>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
@ -18,7 +21,7 @@ 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 char expressionError[256]; static std::string expressionError;
typedef struct { typedef struct {
char Name[4]; char Name[4];
@ -85,8 +88,6 @@ bool parseNumber(char* str, int defaultrad, int len, u64& result)
str+=2; str+=2;
len-=2; len-=2;
} else { } else {
if (!(str[0] >= '0' && str[0] <= '9')) return false;
if (tolower(str[len-1]) == 'b' && defaultrad != 16) if (tolower(str[len-1]) == 'b' && defaultrad != 16)
{ {
r = 2; r = 2;
@ -210,7 +211,7 @@ bool isAlphaNum(char c)
bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, PostfixExpression& dest) bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, PostfixExpression& dest)
{ {
expressionError[0] = 0; expressionError.clear();
int infixPos = 0; int infixPos = 0;
int infixLen = (int)strlen(infix); int infixLen = (int)strlen(infix);
@ -232,19 +233,26 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
if (first >= '0' && first <= '9') if (first >= '0' && first <= '9')
{ {
while (isAlphaNum(infix[infixPos])) while (isAlphaNum(infix[infixPos]) && subPos < static_cast<int>(sizeof(subStr)) - 1)
{ {
subStr[subPos++] = infix[infixPos++]; subStr[subPos++] = infix[infixPos++];
} }
subStr[subPos] = 0; subStr[subPos] = 0;
if(subPos == sizeof(subStr) - 1)
{
expressionError = TRANSLATE("ExpressionParser", "Token too long.");
return false;
}
u64 value; u64 value;
bool isFloat = false; bool isFloat = false;
if (parseFloat(subStr,subPos,value)) if (parseFloat(subStr,subPos,value))
isFloat = true; isFloat = true;
else if (!parseNumber(subStr,16,subPos,value)) else if (!parseNumber(subStr,16,subPos,value))
{ {
std::snprintf(expressionError, std::size(expressionError),"Invalid number \"%s\"",subStr); expressionError = StringUtil::StdStringFromFormat(
TRANSLATE("ExpressionParser", "Invalid number \"%s\"."), subStr);
return false; return false;
} }
@ -252,12 +260,18 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
lastOpcode = EXOP_NUMBER; lastOpcode = EXOP_NUMBER;
} else if ((first >= 'a' && first <= 'z') || first == '@') } else if ((first >= 'a' && first <= 'z') || first == '@')
{ {
while (isAlphaNum(infix[infixPos])) while (isAlphaNum(infix[infixPos]) && subPos < static_cast<int>(sizeof(subStr)) - 1)
{ {
subStr[subPos++] = infix[infixPos++]; subStr[subPos++] = infix[infixPos++];
} }
subStr[subPos] = 0; subStr[subPos] = 0;
if(subPos == sizeof(subStr) - 1)
{
expressionError = TRANSLATE("ExpressionParser", "Token too long.");
return false;
}
u64 value; u64 value;
if (funcs->parseReference(subStr,value)) if (funcs->parseReference(subStr,value))
{ {
@ -273,14 +287,23 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
continue; continue;
} }
std::snprintf(expressionError, std::size(expressionError),"Invalid symbol \"%s\"",subStr); if(parseNumber(subStr,16,subPos,value))
{
dest.push_back(ExpressionPair(EXCOMM_CONST,value));
lastOpcode = EXOP_NUMBER;
continue;
}
expressionError = StringUtil::StdStringFromFormat(
TRANSLATE("ExpressionParser", "Invalid symbol \"%s\"."), subStr);
return false; return false;
} else { } else {
int len; int len;
ExpressionOpcodeType type = getExpressionOpcode(&infix[infixPos],len,lastOpcode); ExpressionOpcodeType type = getExpressionOpcode(&infix[infixPos],len,lastOpcode);
if (type == EXOP_NONE) if (type == EXOP_NONE)
{ {
std::snprintf(expressionError, std::size(expressionError),"Invalid operator at \"%s\"",&infix[infixPos]); expressionError = StringUtil::StdStringFromFormat(
TRANSLATE("ExpressionParser", "Invalid operator at \"%s\"."), &infix[infixPos]);
return false; return false;
} }
@ -295,7 +318,7 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
{ {
if (opcodeStack.empty()) if (opcodeStack.empty())
{ {
std::snprintf(expressionError, std::size(expressionError),"Closing parenthesis without opening one"); expressionError = TRANSLATE("ExpressionParser", "Closing parenthesis without opening one.");
return false; return false;
} }
ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1]; ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1];
@ -309,7 +332,7 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
{ {
if (opcodeStack.empty()) if (opcodeStack.empty())
{ {
std::snprintf(expressionError, std::size(expressionError),"Closing bracket without opening one"); expressionError = TRANSLATE("ExpressionParser", "Closing bracket without opening one.");
return false; return false;
} }
ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1]; ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1];
@ -362,7 +385,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
{ {
std::snprintf(expressionError, std::size(expressionError),"Parenthesis not closed"); expressionError = TRANSLATE("ExpressionParser", "Parenthesis not closed.");
return false; return false;
} }
dest.push_back(ExpressionPair(EXCOMM_OP,t)); dest.push_back(ExpressionPair(EXCOMM_OP,t));
@ -421,7 +444,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)
{ {
std::snprintf(expressionError, std::size(expressionError),"Not enough arguments"); expressionError = 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++)
@ -436,7 +459,7 @@ 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)
{ {
std::snprintf(expressionError, std::size(expressionError),"Invalid memsize operator"); expressionError = TRANSLATE("ExpressionParser", "Invalid memsize operator.");
return false; return false;
} }
@ -480,7 +503,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)
{ {
std::snprintf(expressionError, std::size(expressionError),"Division by zero"); expressionError = TRANSLATE("ExpressionParser", "Division by zero.");
return false; return false;
} }
if (useFloat) if (useFloat)
@ -491,7 +514,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)
{ {
std::snprintf(expressionError, std::size(expressionError),"Modulo by zero"); expressionError = TRANSLATE("ExpressionParser", "Modulo by zero.");
return false; return false;
} }
valueStack.push_back(arg[1]%arg[0]); valueStack.push_back(arg[1]%arg[0]);
@ -570,7 +593,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)
{ {
std::snprintf(expressionError, std::size(expressionError),"Invalid tertiary operator"); expressionError = 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]);
@ -594,6 +617,8 @@ bool parseExpression(char* exp, IExpressionFunctions* funcs, u64& dest)
const char* getExpressionError() const char* getExpressionError()
{ {
if (expressionError[0] == 0) strcpy(expressionError,"Invalid expression"); if (expressionError.empty())
return expressionError; return TRANSLATE("ExpressionParser", "Invalid expression.");
return expressionError.c_str();
} }

View File

@ -22,7 +22,7 @@ public:
virtual bool parseSymbol(char* str, u64& symbolValue) = 0; virtual bool parseSymbol(char* str, u64& symbolValue) = 0;
virtual u64 getReferenceValue(u64 referenceIndex) = 0; virtual u64 getReferenceValue(u64 referenceIndex) = 0;
virtual ExpressionType getReferenceType(u64 referenceIndex) = 0; virtual ExpressionType getReferenceType(u64 referenceIndex) = 0;
virtual bool getMemoryValue(u32 address, int size, u64& dest, char* 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);