mirror of https://github.com/PCSX2/pcsx2.git
Debugger: Bring back the expression parser
This commit is contained in:
parent
f340b5ebd0
commit
90463a4a6c
|
@ -93,10 +93,9 @@ void BreakpointDialog::accept()
|
|||
PostfixExpression expr;
|
||||
|
||||
u64 address;
|
||||
if (!m_cpu->initExpression(m_ui.txtAddress->text().toLocal8Bit().constData(), expr) ||
|
||||
!m_cpu->parseExpression(expr, address))
|
||||
if (!m_cpu->evaluateExpression(m_ui.txtAddress->text().toStdString().c_str(), address))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Error"), tr("Invalid address \"%1\"").arg(m_ui.txtAddress->text()));
|
||||
QMessageBox::warning(this, tr("Invalid Address"), getExpressionError());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -109,9 +108,9 @@ void BreakpointDialog::accept()
|
|||
bp->hasCond = true;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -121,21 +120,17 @@ void BreakpointDialog::accept()
|
|||
}
|
||||
if (auto* mc = std::get_if<MemCheck>(&m_bp_mc))
|
||||
{
|
||||
PostfixExpression expr;
|
||||
|
||||
u64 startAddress;
|
||||
if (!m_cpu->initExpression(m_ui.txtAddress->text().toLocal8Bit().constData(), expr) ||
|
||||
!m_cpu->parseExpression(expr, startAddress))
|
||||
if (!m_cpu->evaluateExpression(m_ui.txtAddress->text().toStdString().c_str(), startAddress))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Error"), tr("Invalid address \"%1\"").arg(m_ui.txtAddress->text()));
|
||||
QMessageBox::warning(this, tr("Invalid Address"), getExpressionError());
|
||||
return;
|
||||
}
|
||||
|
||||
u64 size;
|
||||
if (!m_cpu->initExpression(m_ui.txtSize->text().toLocal8Bit(), expr) ||
|
||||
!m_cpu->parseExpression(expr, size) || !size)
|
||||
if (!m_cpu->evaluateExpression(m_ui.txtSize->text().toStdString().c_str(), size) || !size)
|
||||
{
|
||||
QMessageBox::warning(this, tr("Error"), tr("Invalid size \"%1\"").arg(m_ui.txtSize->text()));
|
||||
QMessageBox::warning(this, tr("Invalid Size"), getExpressionError());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -147,9 +142,10 @@ void BreakpointDialog::accept()
|
|||
mc->hasCond = true;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -163,21 +163,20 @@ void DisassemblyWidget::contextFollowBranch()
|
|||
void DisassemblyWidget::contextGoToAddress()
|
||||
{
|
||||
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);
|
||||
|
||||
if (!ok)
|
||||
return;
|
||||
|
||||
const u32 targetAddress = targetString.toUInt(&ok, 16) & ~3;
|
||||
|
||||
if (!ok)
|
||||
u64 address = 0;
|
||||
if (!m_cpu->evaluateExpression(targetString.toStdString().c_str(), address))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Go to address error"), tr("Invalid address"));
|
||||
QMessageBox::warning(this, tr("Cannot Go To"), getExpressionError());
|
||||
return;
|
||||
}
|
||||
|
||||
gotoAddressAndSetFocus(targetAddress);
|
||||
gotoAddressAndSetFocus(static_cast<u32>(address) & ~3);
|
||||
}
|
||||
|
||||
void DisassemblyWidget::contextAddFunction()
|
||||
|
|
|
@ -592,21 +592,20 @@ void MemoryViewWidget::contextPaste()
|
|||
void MemoryViewWidget::contextGoToAddress()
|
||||
{
|
||||
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);
|
||||
|
||||
if (!ok)
|
||||
return;
|
||||
|
||||
const u32 targetAddress = targetString.toUInt(&ok, 16);
|
||||
|
||||
if (!ok)
|
||||
u64 address = 0;
|
||||
if (!m_cpu->evaluateExpression(targetString.toStdString().c_str(), address))
|
||||
{
|
||||
QMessageBox::warning(this, "Go to address error", "Invalid address");
|
||||
QMessageBox::warning(this, tr("Cannot Go To"), getExpressionError());
|
||||
return;
|
||||
}
|
||||
|
||||
gotoAddress(targetAddress);
|
||||
gotoAddress(static_cast<u32>(address));
|
||||
}
|
||||
|
||||
void MemoryViewWidget::mouseDoubleClickEvent(QMouseEvent* event)
|
||||
|
|
|
@ -25,6 +25,7 @@ public:
|
|||
Tag tag = OBJECT;
|
||||
ccc::MultiSymbolHandle symbol;
|
||||
QString name;
|
||||
QString mangled_name;
|
||||
SymbolTreeLocation location;
|
||||
bool is_location_editable = false;
|
||||
std::optional<u32> size;
|
||||
|
|
|
@ -362,6 +362,13 @@ void SymbolTreeWidget::setupMenu()
|
|||
connect(copy_name, &QAction::triggered, this, &SymbolTreeWidget::onCopyName);
|
||||
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);
|
||||
connect(copy_location, &QAction::triggered, this, &SymbolTreeWidget::onCopyLocation);
|
||||
m_context_menu->addAction(copy_location);
|
||||
|
@ -484,6 +491,18 @@ void SymbolTreeWidget::onCopyName()
|
|||
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()
|
||||
{
|
||||
SymbolTreeNode* node = currentNode();
|
||||
|
@ -611,7 +630,7 @@ SymbolTreeNode* SymbolTreeWidget::currentNode()
|
|||
// *****************************************************************************
|
||||
|
||||
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>();
|
||||
node->name = std::move(work.name);
|
||||
node->mangled_name = QString::fromStdString(function.mangled_name());
|
||||
node->location = SymbolTreeLocation(SymbolTreeLocation::MEMORY, function.address().value);
|
||||
node->size = function.size();
|
||||
node->symbol = ccc::MultiSymbolHandle(function);
|
||||
|
@ -694,7 +714,7 @@ void FunctionTreeWidget::onNewButtonPressed()
|
|||
// *****************************************************************************
|
||||
|
||||
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);
|
||||
|
||||
node->mangled_name = QString::fromStdString(global_variable.mangled_name());
|
||||
if (global_variable.type())
|
||||
node->type = ccc::NodeHandle(global_variable, global_variable.type());
|
||||
node->location = SymbolTreeLocation(SymbolTreeLocation::MEMORY, global_variable.address().value);
|
||||
|
|
|
@ -84,6 +84,7 @@ protected:
|
|||
void onDeleteButtonPressed();
|
||||
|
||||
void onCopyName();
|
||||
void onCopyMangledName();
|
||||
void onCopyLocation();
|
||||
void onRenameSymbol();
|
||||
void onGoToInDisassembly();
|
||||
|
@ -117,7 +118,8 @@ protected:
|
|||
NO_SYMBOL_TREE_FLAGS = 0,
|
||||
ALLOW_GROUPING = 1 << 0,
|
||||
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;
|
||||
|
|
|
@ -10,17 +10,13 @@
|
|||
#include "GS.h" // Required for gsNonMirroredRead()
|
||||
#include "Counters.h"
|
||||
|
||||
#include "Host.h"
|
||||
#include "R3000A.h"
|
||||
#include "IopMem.h"
|
||||
#include "VMManager.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;
|
||||
R3000DebugInterface r3000Debug;
|
||||
|
||||
|
@ -45,8 +41,20 @@ enum ReferenceIndexType
|
|||
class MipsExpressionFunctions : public IExpressionFunctions
|
||||
{
|
||||
public:
|
||||
explicit MipsExpressionFunctions(DebugInterface* cpu)
|
||||
: cpu(cpu){};
|
||||
explicit MipsExpressionFunctions(DebugInterface* cpu, bool enumerateSymbols)
|
||||
: 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)
|
||||
{
|
||||
|
@ -54,7 +62,7 @@ public:
|
|||
{
|
||||
char reg[8];
|
||||
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;
|
||||
return true;
|
||||
|
@ -108,27 +116,62 @@ public:
|
|||
|
||||
virtual bool parseSymbol(char* str, u64& symbolValue)
|
||||
{
|
||||
SymbolInfo symbol = cpu->GetSymbolGuardian().SymbolWithName(std::string(str));
|
||||
if (!symbol.address.valid())
|
||||
return false;
|
||||
bool success = false;
|
||||
m_cpu->GetSymbolGuardian().Read([&](const ccc::SymbolDatabase& database) {
|
||||
std::string name = str;
|
||||
|
||||
symbolValue = symbol.address.value;
|
||||
return true;
|
||||
// Check for mangled function names.
|
||||
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)
|
||||
{
|
||||
if (referenceIndex < 32)
|
||||
return cpu->getRegister(0, referenceIndex)._u64[0];
|
||||
return m_cpu->getRegister(0, referenceIndex)._u64[0];
|
||||
if (referenceIndex == REF_INDEX_PC)
|
||||
return cpu->getPC();
|
||||
return m_cpu->getPC();
|
||||
if (referenceIndex == REF_INDEX_HI)
|
||||
return cpu->getHI()._u64[0];
|
||||
return m_cpu->getHI()._u64[0];
|
||||
if (referenceIndex == REF_INDEX_LO)
|
||||
return cpu->getLO()._u64[0];
|
||||
return m_cpu->getLO()._u64[0];
|
||||
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);
|
||||
if (opcode.flags & IS_MEMORY)
|
||||
{
|
||||
|
@ -154,7 +197,7 @@ public:
|
|||
}
|
||||
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;
|
||||
}
|
||||
|
@ -168,7 +211,7 @@ public:
|
|||
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)
|
||||
{
|
||||
|
@ -178,37 +221,40 @@ public:
|
|||
case 8:
|
||||
break;
|
||||
default:
|
||||
sprintf(error, "Invalid memory access size %d", size);
|
||||
error = StringUtil::StdStringFromFormat(
|
||||
TRANSLATE("ExpressionParser", "Invalid memory access size %d."), size);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (address % size)
|
||||
{
|
||||
sprintf(error, "Invalid memory access (unaligned)");
|
||||
error = TRANSLATE("ExpressionParser", "Invalid memory access (unaligned).");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (size)
|
||||
{
|
||||
case 1:
|
||||
dest = cpu->read8(address);
|
||||
dest = m_cpu->read8(address);
|
||||
break;
|
||||
case 2:
|
||||
dest = cpu->read16(address);
|
||||
dest = m_cpu->read16(address);
|
||||
break;
|
||||
case 4:
|
||||
dest = cpu->read32(address);
|
||||
dest = m_cpu->read32(address);
|
||||
break;
|
||||
case 8:
|
||||
dest = cpu->read64(address);
|
||||
dest = m_cpu->read64(address);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
DebugInterface* cpu;
|
||||
protected:
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
MipsExpressionFunctions funcs(this);
|
||||
MipsExpressionFunctions funcs(this, true);
|
||||
return initPostfixExpression(exp, &funcs, dest);
|
||||
}
|
||||
|
||||
bool DebugInterface::parseExpression(PostfixExpression& exp, u64& dest)
|
||||
{
|
||||
MipsExpressionFunctions funcs(this);
|
||||
MipsExpressionFunctions funcs(this, false);
|
||||
return parsePostfixExpression(exp, &funcs, dest);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// R5900DebugInterface
|
||||
//
|
||||
|
|
|
@ -79,6 +79,7 @@ public:
|
|||
[[nodiscard]] virtual SymbolGuardian& GetSymbolGuardian() 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 parseExpression(PostfixExpression& exp, u64& dest);
|
||||
bool isAlive();
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
|
||||
#include "ExpressionParser.h"
|
||||
|
||||
#include "Host.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
@ -18,7 +21,7 @@ typedef enum {
|
|||
|
||||
typedef enum { EXCOMM_CONST, EXCOMM_CONST_FLOAT, EXCOMM_REF, EXCOMM_OP } ExpressionCommand;
|
||||
|
||||
static char expressionError[256];
|
||||
static std::string expressionError;
|
||||
|
||||
typedef struct {
|
||||
char Name[4];
|
||||
|
@ -85,8 +88,6 @@ bool parseNumber(char* str, int defaultrad, int len, u64& result)
|
|||
str+=2;
|
||||
len-=2;
|
||||
} else {
|
||||
if (!(str[0] >= '0' && str[0] <= '9')) return false;
|
||||
|
||||
if (tolower(str[len-1]) == 'b' && defaultrad != 16)
|
||||
{
|
||||
r = 2;
|
||||
|
@ -210,7 +211,7 @@ bool isAlphaNum(char c)
|
|||
|
||||
bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, PostfixExpression& dest)
|
||||
{
|
||||
expressionError[0] = 0;
|
||||
expressionError.clear();
|
||||
|
||||
int infixPos = 0;
|
||||
int infixLen = (int)strlen(infix);
|
||||
|
@ -232,19 +233,26 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
|
|||
|
||||
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] = 0;
|
||||
|
||||
if(subPos == sizeof(subStr) - 1)
|
||||
{
|
||||
expressionError = TRANSLATE("ExpressionParser", "Token too long.");
|
||||
return false;
|
||||
}
|
||||
|
||||
u64 value;
|
||||
bool isFloat = false;
|
||||
if (parseFloat(subStr,subPos,value))
|
||||
isFloat = true;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -252,12 +260,18 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
|
|||
lastOpcode = EXOP_NUMBER;
|
||||
} 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] = 0;
|
||||
|
||||
if(subPos == sizeof(subStr) - 1)
|
||||
{
|
||||
expressionError = TRANSLATE("ExpressionParser", "Token too long.");
|
||||
return false;
|
||||
}
|
||||
|
||||
u64 value;
|
||||
if (funcs->parseReference(subStr,value))
|
||||
{
|
||||
|
@ -273,14 +287,23 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
|
|||
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;
|
||||
} else {
|
||||
int len;
|
||||
ExpressionOpcodeType type = getExpressionOpcode(&infix[infixPos],len,lastOpcode);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -295,7 +318,7 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
|
|||
{
|
||||
if (opcodeStack.empty())
|
||||
{
|
||||
std::snprintf(expressionError, std::size(expressionError),"Closing parenthesis without opening one");
|
||||
expressionError = TRANSLATE("ExpressionParser", "Closing parenthesis without opening one.");
|
||||
return false;
|
||||
}
|
||||
ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1];
|
||||
|
@ -309,7 +332,7 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
|
|||
{
|
||||
if (opcodeStack.empty())
|
||||
{
|
||||
std::snprintf(expressionError, std::size(expressionError),"Closing bracket without opening one");
|
||||
expressionError = TRANSLATE("ExpressionParser", "Closing bracket without opening one.");
|
||||
return false;
|
||||
}
|
||||
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
|
||||
{
|
||||
std::snprintf(expressionError, std::size(expressionError),"Parenthesis not closed");
|
||||
expressionError = TRANSLATE("ExpressionParser", "Parenthesis not closed.");
|
||||
return false;
|
||||
}
|
||||
dest.push_back(ExpressionPair(EXCOMM_OP,t));
|
||||
|
@ -421,7 +444,7 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs,
|
|||
opcode = exp[num++].second;
|
||||
if (valueStack.size() < ExpressionOpcodes[opcode].args)
|
||||
{
|
||||
std::snprintf(expressionError, std::size(expressionError),"Not enough arguments");
|
||||
expressionError = TRANSLATE("ExpressionParser", "Not enough arguments.");
|
||||
return false;
|
||||
}
|
||||
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
|
||||
if (exp[num++].second != EXOP_MEM)
|
||||
{
|
||||
std::snprintf(expressionError, std::size(expressionError),"Invalid memsize operator");
|
||||
expressionError = TRANSLATE("ExpressionParser", "Invalid memsize operator.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -480,7 +503,7 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs,
|
|||
case EXOP_DIV: // a/b
|
||||
if (arg[0] == 0)
|
||||
{
|
||||
std::snprintf(expressionError, std::size(expressionError),"Division by zero");
|
||||
expressionError = TRANSLATE("ExpressionParser", "Division by zero.");
|
||||
return false;
|
||||
}
|
||||
if (useFloat)
|
||||
|
@ -491,7 +514,7 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs,
|
|||
case EXOP_MOD: // a%b
|
||||
if (arg[0] == 0)
|
||||
{
|
||||
std::snprintf(expressionError, std::size(expressionError),"Modulo by zero");
|
||||
expressionError = TRANSLATE("ExpressionParser", "Modulo by zero.");
|
||||
return false;
|
||||
}
|
||||
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!
|
||||
if (exp[num++].second != EXOP_TERTIF)
|
||||
{
|
||||
std::snprintf(expressionError, std::size(expressionError),"Invalid tertiary operator");
|
||||
expressionError = TRANSLATE("ExpressionParser", "Invalid tertiary operator.");
|
||||
return false;
|
||||
}
|
||||
valueStack.push_back(arg[2]?arg[1]:arg[0]);
|
||||
|
@ -594,6 +617,8 @@ bool parseExpression(char* exp, IExpressionFunctions* funcs, u64& dest)
|
|||
|
||||
const char* getExpressionError()
|
||||
{
|
||||
if (expressionError[0] == 0) strcpy(expressionError,"Invalid expression");
|
||||
return expressionError;
|
||||
if (expressionError.empty())
|
||||
return TRANSLATE("ExpressionParser", "Invalid expression.");
|
||||
|
||||
return expressionError.c_str();
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ public:
|
|||
virtual bool parseSymbol(char* str, u64& symbolValue) = 0;
|
||||
virtual u64 getReferenceValue(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);
|
||||
|
|
Loading…
Reference in New Issue