Expression parser
This commit is contained in:
parent
88b9fa7345
commit
ab1aa09dce
13 changed files with 577 additions and 21 deletions
|
@ -1022,6 +1022,8 @@ if(WIN32)
|
||||||
Windows/Debugger/Debugger_SymbolMap.h
|
Windows/Debugger/Debugger_SymbolMap.h
|
||||||
Windows/Debugger/Debugger_VFPUDlg.cpp
|
Windows/Debugger/Debugger_VFPUDlg.cpp
|
||||||
Windows/Debugger/Debugger_VFPUDlg.h
|
Windows/Debugger/Debugger_VFPUDlg.h
|
||||||
|
Windows/Debugger/ExpressionParser.cpp
|
||||||
|
Windows/Debugger/ExpressionParser.h
|
||||||
Windows/Debugger/SimpleELF.h
|
Windows/Debugger/SimpleELF.h
|
||||||
# Windows/DlgDynaView.cpp
|
# Windows/DlgDynaView.cpp
|
||||||
# Windows/DlgDynaView.h
|
# Windows/DlgDynaView.h
|
||||||
|
|
|
@ -41,6 +41,7 @@ public:
|
||||||
virtual int getColor(unsigned int address){return 0xFFFFFFFF;}
|
virtual int getColor(unsigned int address){return 0xFFFFFFFF;}
|
||||||
virtual const char *getDescription(unsigned int address) {return "";}
|
virtual const char *getDescription(unsigned int address) {return "";}
|
||||||
virtual const char *findSymbolForAddress(unsigned int address) { return NULL; };
|
virtual const char *findSymbolForAddress(unsigned int address) { return NULL; };
|
||||||
|
virtual bool getSymbolValue(char* symbol, u32& dest) { return false; };
|
||||||
|
|
||||||
virtual const char *GetName() = 0;
|
virtual const char *GetName() = 0;
|
||||||
virtual int GetGPRSize() = 0; //32 or 64
|
virtual int GetGPRSize() = 0; //32 or 64
|
||||||
|
|
|
@ -237,6 +237,20 @@ const char* SymbolMap::getDirectSymbol(u32 address)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SymbolMap::getSymbolValue(char* symbol, u32& dest)
|
||||||
|
{
|
||||||
|
for (size_t i = 0, n = entries.size(); i < n; i++)
|
||||||
|
{
|
||||||
|
MapEntry &entry = entries[i];
|
||||||
|
if (stricmp(entry.name,symbol) == 0)
|
||||||
|
{
|
||||||
|
dest = entries[i].address;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
char descriptionTemp[256];
|
char descriptionTemp[256];
|
||||||
|
|
||||||
char *SymbolMap::GetDescription(unsigned int address)
|
char *SymbolMap::GetDescription(unsigned int address)
|
||||||
|
|
|
@ -59,6 +59,7 @@ public:
|
||||||
unsigned int GetRunCount(int num);
|
unsigned int GetRunCount(int num);
|
||||||
void SortSymbols();
|
void SortSymbols();
|
||||||
const char* getDirectSymbol(u32 address);
|
const char* getDirectSymbol(u32 address);
|
||||||
|
bool getSymbolValue(char* symbol, u32& dest);
|
||||||
|
|
||||||
void UseFuncSignaturesFile(const char *filename, u32 maxAddress);
|
void UseFuncSignaturesFile(const char *filename, u32 maxAddress);
|
||||||
void CompileFuncSignaturesFile(const char *filename);
|
void CompileFuncSignaturesFile(const char *filename);
|
||||||
|
|
|
@ -86,6 +86,12 @@ const char *MIPSDebugInterface::findSymbolForAddress(unsigned int address)
|
||||||
return symbolMap.getDirectSymbol(address);
|
return symbolMap.getDirectSymbol(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MIPSDebugInterface::getSymbolValue(char* symbol, u32& dest)
|
||||||
|
{
|
||||||
|
return symbolMap.getSymbolValue(symbol,dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void MIPSDebugInterface::runToBreakpoint()
|
void MIPSDebugInterface::runToBreakpoint()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ public:
|
||||||
virtual int getColor(unsigned int address);
|
virtual int getColor(unsigned int address);
|
||||||
virtual const char *getDescription(unsigned int address);
|
virtual const char *getDescription(unsigned int address);
|
||||||
virtual const char *findSymbolForAddress(unsigned int address);
|
virtual const char *findSymbolForAddress(unsigned int address);
|
||||||
|
virtual bool getSymbolValue(char* symbol, u32& dest);
|
||||||
|
|
||||||
//overridden functions
|
//overridden functions
|
||||||
const char *GetName();
|
const char *GetName();
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include "../../globals.h"
|
#include "../../globals.h"
|
||||||
#include "Debugger_Disasm.h"
|
#include "Debugger_Disasm.h"
|
||||||
|
#include "ExpressionParser.h"
|
||||||
|
|
||||||
#include "../main.h"
|
#include "../main.h"
|
||||||
|
|
||||||
|
@ -360,10 +361,18 @@ void CtrlRegisterList::editRegisterValue()
|
||||||
return;
|
return;
|
||||||
u32 val = cpu->GetRegValue(cat,reg);
|
u32 val = cpu->GetRegValue(cat,reg);
|
||||||
|
|
||||||
if (InputBox_GetHex(GetModuleHandle(NULL),wnd,"Set new value",val,val))
|
|
||||||
|
char temp[256];
|
||||||
|
sprintf(temp,"%08X",val);
|
||||||
|
if (InputBox_GetString(GetModuleHandle(NULL),wnd,"Set new value",temp,temp))
|
||||||
{
|
{
|
||||||
cpu->SetRegValue(cat,reg,val);
|
if (parseExpression(temp,cpu,val) == false)
|
||||||
redraw();
|
{
|
||||||
|
displayExpressionError(wnd);
|
||||||
|
} else {
|
||||||
|
cpu->SetRegValue(cat,reg,val);
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "Debugger_MemoryDlg.h"
|
#include "Debugger_MemoryDlg.h"
|
||||||
#include "Debugger_Disasm.h"
|
#include "Debugger_Disasm.h"
|
||||||
#include "Debugger_VFPUDlg.h"
|
#include "Debugger_VFPUDlg.h"
|
||||||
|
#include "ExpressionParser.h"
|
||||||
|
|
||||||
#include "../main.h"
|
#include "../main.h"
|
||||||
#include "CtrlRegisterList.h"
|
#include "CtrlRegisterList.h"
|
||||||
|
@ -66,6 +67,24 @@ static LRESULT CALLBACK BreakpointListProc(HWND hDlg, UINT message, WPARAM wPara
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
FAR WNDPROC DefGotoEditProc;
|
||||||
|
|
||||||
|
LRESULT CALLBACK GotoEditProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
switch(message)
|
||||||
|
{
|
||||||
|
case WM_KEYUP:
|
||||||
|
if( wParam == VK_RETURN )
|
||||||
|
{
|
||||||
|
SendMessage(GetParent(hDlg),WM_USER+6,0,0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return (LRESULT)CallWindowProc((WNDPROC)DefGotoEditProc,hDlg,message,wParam,lParam);
|
||||||
|
};
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
CDisasm::CDisasm(HINSTANCE _hInstance, HWND _hParent, DebugInterface *_cpu) : Dialog((LPCSTR)IDD_DISASM, _hInstance, _hParent)
|
CDisasm::CDisasm(HINSTANCE _hInstance, HWND _hParent, DebugInterface *_cpu) : Dialog((LPCSTR)IDD_DISASM, _hInstance, _hParent)
|
||||||
|
@ -124,7 +143,11 @@ CDisasm::CDisasm(HINSTANCE _hInstance, HWND _hParent, DebugInterface *_cpu) : Di
|
||||||
ShowWindow(GetDlgItem(m_hDlg, IDC_REGLIST), SW_NORMAL);
|
ShowWindow(GetDlgItem(m_hDlg, IDC_REGLIST), SW_NORMAL);
|
||||||
ShowWindow(GetDlgItem(m_hDlg, IDC_FUNCTIONLIST), SW_HIDE);
|
ShowWindow(GetDlgItem(m_hDlg, IDC_FUNCTIONLIST), SW_HIDE);
|
||||||
SetTimer(m_hDlg,1,1000,0);
|
SetTimer(m_hDlg,1,1000,0);
|
||||||
|
|
||||||
|
// subclass the goto edit box
|
||||||
|
HWND editWnd = GetDlgItem(m_hDlg,IDC_ADDRESS);
|
||||||
|
DefGotoEditProc = (WNDPROC)GetWindowLongPtr(editWnd,GWLP_WNDPROC);
|
||||||
|
SetWindowLongPtr(editWnd,GWLP_WNDPROC,(LONG_PTR)DefGotoEditProc);
|
||||||
|
|
||||||
// subclass the breakpoint list
|
// subclass the breakpoint list
|
||||||
HWND breakpointHwnd = GetDlgItem(m_hDlg, IDC_BREAKPOINTLIST);
|
HWND breakpointHwnd = GetDlgItem(m_hDlg, IDC_BREAKPOINTLIST);
|
||||||
|
@ -147,7 +170,6 @@ CDisasm::CDisasm(HINSTANCE _hInstance, HWND _hParent, DebugInterface *_cpu) : Di
|
||||||
ListView_InsertColumn(breakpointHwnd, i, &lvc);
|
ListView_InsertColumn(breakpointHwnd, i, &lvc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Actually resize the window to the proper size (after the above setup.)
|
// Actually resize the window to the proper size (after the above setup.)
|
||||||
if (w != -1 && h != -1)
|
if (w != -1 && h != -1)
|
||||||
{
|
{
|
||||||
|
@ -584,7 +606,8 @@ BOOL CDisasm::DlgProc(UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
}
|
}
|
||||||
|
|
||||||
MemCheck check;
|
MemCheck check;
|
||||||
if (InputBox_GetHex(GetModuleHandle(NULL), m_hDlg, "JIT (and not HLE) only for now, no delete", 0, check.iStartAddress))
|
|
||||||
|
if (executeExpressionWindow(m_hDlg,cpu,check.iStartAddress))
|
||||||
{
|
{
|
||||||
check.bBreak = true;
|
check.bBreak = true;
|
||||||
check.bLog = true;
|
check.bLog = true;
|
||||||
|
@ -603,19 +626,6 @@ BOOL CDisasm::DlgProc(UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IDC_ADDRESS:
|
|
||||||
{
|
|
||||||
if (HIWORD(wParam) == EN_CHANGE )
|
|
||||||
{
|
|
||||||
char szBuffer[32];
|
|
||||||
GetWindowText ((HWND)lParam, szBuffer, 32);
|
|
||||||
ptr->gotoAddr(parseHex(szBuffer));
|
|
||||||
UpdateDialog();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IDC_UPDATECALLSTACK:
|
case IDC_UPDATECALLSTACK:
|
||||||
{
|
{
|
||||||
HWND hDlg = m_hDlg;
|
HWND hDlg = m_hDlg;
|
||||||
|
@ -700,6 +710,22 @@ BOOL CDisasm::DlgProc(UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
case WM_USER+5:
|
case WM_USER+5:
|
||||||
removeBreakpoint(wParam);
|
removeBreakpoint(wParam);
|
||||||
break;
|
break;
|
||||||
|
case WM_USER+6: // goto edit
|
||||||
|
{
|
||||||
|
char szBuffer[256];
|
||||||
|
CtrlDisAsmView *ptr = CtrlDisAsmView::getFrom(GetDlgItem(m_hDlg,IDC_DISASMVIEW));
|
||||||
|
GetWindowText(GetDlgItem(m_hDlg,IDC_ADDRESS),szBuffer,256);
|
||||||
|
|
||||||
|
u32 addr;
|
||||||
|
if (parseExpression(szBuffer,cpu,addr) == false)
|
||||||
|
{
|
||||||
|
displayExpressionError(m_hDlg);
|
||||||
|
} else {
|
||||||
|
ptr->gotoAddr(addr);
|
||||||
|
}
|
||||||
|
UpdateDialog();
|
||||||
|
}
|
||||||
|
break;
|
||||||
case WM_SIZE:
|
case WM_SIZE:
|
||||||
{
|
{
|
||||||
UpdateSize(LOWORD(lParam), HIWORD(lParam));
|
UpdateSize(LOWORD(lParam), HIWORD(lParam));
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "Debugger_MemoryDlg.h"
|
#include "Debugger_MemoryDlg.h"
|
||||||
|
|
||||||
#include "CtrlMemView.h"
|
#include "CtrlMemView.h"
|
||||||
|
#include "ExpressionParser.h"
|
||||||
|
|
||||||
#include "../../Core/MIPS/MIPSDebugInterface.h" // BAD
|
#include "../../Core/MIPS/MIPSDebugInterface.h" // BAD
|
||||||
|
|
||||||
|
@ -156,8 +157,13 @@ BOOL CMemoryDlg::DlgProc(UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
char temp[256];
|
char temp[256];
|
||||||
u32 addr;
|
u32 addr;
|
||||||
GetWindowText(GetDlgItem(m_hDlg,IDC_ADDRESS),temp,255);
|
GetWindowText(GetDlgItem(m_hDlg,IDC_ADDRESS),temp,255);
|
||||||
sscanf(temp,"%08x",&addr);
|
|
||||||
mv->gotoAddr(addr);
|
if (parseExpression(temp,cpu,addr) == false)
|
||||||
|
{
|
||||||
|
displayExpressionError(m_hDlg);
|
||||||
|
} else {
|
||||||
|
mv->gotoAddr(addr);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case WM_INITDIALOG:
|
case WM_INITDIALOG:
|
||||||
|
|
474
Windows/Debugger/ExpressionParser.cpp
Normal file
474
Windows/Debugger/ExpressionParser.cpp
Normal file
|
@ -0,0 +1,474 @@
|
||||||
|
#include "ExpressionParser.h"
|
||||||
|
#include "../../Core/MIPS/MIPSDebugInterface.h"
|
||||||
|
#include "../InputBox.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EXOP_BRACKETL, EXOP_BRACKETR, EXOP_SIGNPLUS, EXOP_SIGNMINUS,
|
||||||
|
EXOP_BITNOT, EXOP_LOGNOT, EXOP_MUL, EXOP_DIV, EXOP_MOD, EXOP_ADD, EXOP_SUB,
|
||||||
|
EXOP_SHL, EXOP_SHR, EXOP_GREATEREQUAL, EXOP_GREATER, EXOP_LOWEREQUAL, EXOP_LOWER,
|
||||||
|
EXOP_EQUAL, EXOP_NOTEQUAL, EXOP_BITAND, EXOP_XOR, EXOP_BITOR, EXOP_LOGAND,
|
||||||
|
EXOP_LOGOR, EXOP_TERTIF, EXOP_TERTELSE, EXOP_NUMBER, EXOP_NONE, EXOP_COUNT
|
||||||
|
} ExpressionOpcodeType;
|
||||||
|
|
||||||
|
typedef enum { EXCOMM_CONST, EXCOMM_OP } ExpressionCommand;
|
||||||
|
|
||||||
|
typedef std::pair<ExpressionCommand,u32> ExpressionPair;
|
||||||
|
|
||||||
|
static char expressionError[256];
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char Name[4];
|
||||||
|
unsigned char Priority;
|
||||||
|
unsigned char len;
|
||||||
|
unsigned char args;
|
||||||
|
bool sign;
|
||||||
|
} ExpressionOpcode;
|
||||||
|
|
||||||
|
const ExpressionOpcode ExpressionOpcodes[] = {
|
||||||
|
{ "(", 15, 1, 0, false }, // EXOP_BRACKETL
|
||||||
|
{ ")", 15, 1, 0, false }, // EXOP_BRACKETR
|
||||||
|
{ "+", 12, 1, 1, true }, // EXOP_SIGNPLUS
|
||||||
|
{ "-", 12, 1, 1, true }, // EXOP_SIGNMINUS
|
||||||
|
{ "~", 12, 1, 1, false }, // EXOP_BITNOT
|
||||||
|
{ "!", 12, 1, 1, false }, // EXOP_LOGNOT
|
||||||
|
{ "*", 11, 1, 2, false }, // EXOP_MUL
|
||||||
|
{ "/", 11, 1, 2, false }, // EXOP_DIV
|
||||||
|
{ "%", 11, 1, 2, false }, // EXOP_MOD
|
||||||
|
{ "+", 10, 1, 2, false }, // EXOP_ADD
|
||||||
|
{ "-", 10, 1, 2, false }, // EXOP_SUB
|
||||||
|
{ "<<", 9, 2, 2, false }, // EXOP_SHL
|
||||||
|
{ ">>", 9, 2, 2, false }, // EXOP_SHR
|
||||||
|
{ ">=", 8, 2, 2, false }, // EXOP_GREATEREQUAL
|
||||||
|
{ ">", 8, 1, 2, false }, // EXOP_GREATER
|
||||||
|
{ "<=", 8, 2, 2, false }, // EXOP_LOWEREQUAL
|
||||||
|
{ "<", 8, 1, 2, false }, // EXOP_LOWER
|
||||||
|
{ "==", 7, 2, 2, false }, // EXOP_EQUAL
|
||||||
|
{ "!=", 7, 2, 2, false }, // EXOP_NOTEQUAL
|
||||||
|
{ "&", 6, 1, 2, false }, // EXOP_BITAND
|
||||||
|
{ "^", 5, 1, 2, false }, // EXOP_XOR
|
||||||
|
{ "|", 4, 1, 2, false }, // EXOP_BITOR
|
||||||
|
{ "&&", 3, 2, 2, false }, // EXOP_LOGAND
|
||||||
|
{ "||", 2, 2, 2, false }, // EXOP_LOGOR
|
||||||
|
{ "?", 0, 1, 0, false }, // EXOP_TERTIF
|
||||||
|
{ ":", 1, 1, 3, false }, // EXOP_TERTELSE
|
||||||
|
{ "", 0, 0, 0, false }, // EXOP_NUMBER
|
||||||
|
{ "", 0, 0, 0, false } // EXOP_NONE
|
||||||
|
};
|
||||||
|
|
||||||
|
bool parseNumber(char* str, int defaultrad, int len, u32& result)
|
||||||
|
{
|
||||||
|
int val = 0;
|
||||||
|
int r = 0;
|
||||||
|
if (len == 0) len = (int) strlen(str);
|
||||||
|
|
||||||
|
if (str[0] == '0' && tolower(str[1]) == 'x')
|
||||||
|
{
|
||||||
|
r = 16;
|
||||||
|
str+=2;
|
||||||
|
len-=2;
|
||||||
|
} else if (str[0] == '$')
|
||||||
|
{
|
||||||
|
r = 16;
|
||||||
|
str++;
|
||||||
|
len--;
|
||||||
|
} else if (str[0] == '0' && tolower(str[1]) == 'o')
|
||||||
|
{
|
||||||
|
r = 8;
|
||||||
|
str+=2;
|
||||||
|
len-=2;
|
||||||
|
} else {
|
||||||
|
if (!(str[0] >= '0' && str[0] <= '9')) return false;
|
||||||
|
|
||||||
|
if (tolower(str[len-1]) == 'b')
|
||||||
|
{
|
||||||
|
r = 2;
|
||||||
|
len--;
|
||||||
|
} else if (tolower(str[len-1]) == 'o')
|
||||||
|
{
|
||||||
|
r = 8;
|
||||||
|
len--;
|
||||||
|
} else if (tolower(str[len-1]) == 'h')
|
||||||
|
{
|
||||||
|
r = 16;
|
||||||
|
len--;
|
||||||
|
} else {
|
||||||
|
r = defaultrad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (r)
|
||||||
|
{
|
||||||
|
case 2: // bin
|
||||||
|
while (len--)
|
||||||
|
{
|
||||||
|
if (*str != '0' && *str != '1') return false;
|
||||||
|
val = val << 1;
|
||||||
|
if (*str++ == '1')
|
||||||
|
{
|
||||||
|
val++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 8: // oct
|
||||||
|
while (len--)
|
||||||
|
{
|
||||||
|
if (*str < '0' || *str > '7') return false;
|
||||||
|
val = val << 3;
|
||||||
|
val+=(*str++-'0');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 10: // dec
|
||||||
|
while (len--)
|
||||||
|
{
|
||||||
|
if (*str < '0' || *str > '9') return false;
|
||||||
|
val = val * 10;
|
||||||
|
val += (*str++ - '0');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 16: // hex
|
||||||
|
while (len--)
|
||||||
|
{
|
||||||
|
char c = tolower(*str++);
|
||||||
|
if ((c < '0' || c > '9') && (c < 'a' || c > 'f')) return false;
|
||||||
|
val = val << 4;
|
||||||
|
|
||||||
|
if (c >= 'a') val += c-'a'+10;
|
||||||
|
else val += c-'0';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = val;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parseLabel(char* label, DebugInterface* debug, u32& dest)
|
||||||
|
{
|
||||||
|
// check if it's a register first
|
||||||
|
for (int i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
|
char reg[8];
|
||||||
|
sprintf(reg,"r%d",i);
|
||||||
|
|
||||||
|
if (stricmp(label,reg) == 0
|
||||||
|
|| stricmp(label,debug->GetRegName(0,i)) == 0)
|
||||||
|
{
|
||||||
|
dest = debug->GetRegValue(0,i);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now check labels
|
||||||
|
return debug->getSymbolValue(label,dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionOpcodeType getExpressionOpcode(char* str, int& ReturnLen, ExpressionOpcodeType LastOpcode)
|
||||||
|
{
|
||||||
|
int longestlen = 0;
|
||||||
|
ExpressionOpcodeType result = EXOP_NONE;
|
||||||
|
|
||||||
|
for (int i = 0; i < EXOP_NUMBER; i++)
|
||||||
|
{
|
||||||
|
if (ExpressionOpcodes[i].sign == true &&
|
||||||
|
(LastOpcode == EXOP_NUMBER || LastOpcode == EXOP_BRACKETR)) continue;
|
||||||
|
|
||||||
|
int len = ExpressionOpcodes[i].len;
|
||||||
|
if (len > longestlen)
|
||||||
|
{
|
||||||
|
if (strncmp(ExpressionOpcodes[i].Name,str,len) == 0)
|
||||||
|
{
|
||||||
|
result = (ExpressionOpcodeType) i;
|
||||||
|
longestlen = len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnLen = longestlen;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isAlphaNum(char c)
|
||||||
|
{
|
||||||
|
if ((c >= '0' && c <= '9') ||
|
||||||
|
(c >= 'A' && c <= 'Z') ||
|
||||||
|
(c >= 'a' && c <= 'z') ||
|
||||||
|
c == '@' || c == '_' || c == '$')
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parseExpression(char* infix, DebugInterface* cpu, u32& dest)
|
||||||
|
{
|
||||||
|
expressionError[0] = 0;
|
||||||
|
|
||||||
|
int infixPos = 0;
|
||||||
|
int infixLen = strlen(infix);
|
||||||
|
ExpressionOpcodeType lastOpcode = EXOP_NONE;
|
||||||
|
|
||||||
|
std::vector<ExpressionPair> postfixStack;
|
||||||
|
std::vector<ExpressionOpcodeType> opcodeStack;
|
||||||
|
|
||||||
|
while (infixPos < infixLen)
|
||||||
|
{
|
||||||
|
char first = tolower(infix[infixPos]);
|
||||||
|
char subStr[12];
|
||||||
|
int subPos = 0;
|
||||||
|
|
||||||
|
if (first == ' ' || first == '\t')
|
||||||
|
{
|
||||||
|
infixPos++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first >= '0' && first <= '9')
|
||||||
|
{
|
||||||
|
while (isAlphaNum(infix[infixPos]))
|
||||||
|
{
|
||||||
|
subStr[subPos++] = infix[infixPos++];
|
||||||
|
}
|
||||||
|
subStr[subPos] = 0;
|
||||||
|
|
||||||
|
u32 value;
|
||||||
|
if (parseNumber(subStr,16,subPos,value) == false)
|
||||||
|
{
|
||||||
|
sprintf(expressionError,"Invalid number \"%s\"",subStr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
postfixStack.push_back(ExpressionPair(EXCOMM_CONST,value));
|
||||||
|
lastOpcode = EXOP_NUMBER;
|
||||||
|
} else if ((first >= 'a' && first <= 'z') || first == '@')
|
||||||
|
{
|
||||||
|
while (isAlphaNum(infix[infixPos]))
|
||||||
|
{
|
||||||
|
subStr[subPos++] = infix[infixPos++];
|
||||||
|
}
|
||||||
|
subStr[subPos] = 0;
|
||||||
|
|
||||||
|
u32 value;
|
||||||
|
if (parseLabel(subStr,cpu,value) == false)
|
||||||
|
{
|
||||||
|
sprintf(expressionError,"Invalid label \"%s\"",subStr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
postfixStack.push_back(ExpressionPair(EXCOMM_CONST,value));
|
||||||
|
lastOpcode = EXOP_NUMBER;
|
||||||
|
} else {
|
||||||
|
int len;
|
||||||
|
ExpressionOpcodeType type = getExpressionOpcode(&infix[infixPos],len,lastOpcode);
|
||||||
|
if (type == EXOP_NONE)
|
||||||
|
{
|
||||||
|
sprintf(expressionError,"Invalid operator at \"%s\"",&infix[infixPos]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case EXOP_BRACKETL:
|
||||||
|
opcodeStack.push_back(type);
|
||||||
|
break;
|
||||||
|
case EXOP_BRACKETR:
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (opcodeStack.empty())
|
||||||
|
{
|
||||||
|
sprintf(expressionError,"Closing parenthesis without opening one");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1];
|
||||||
|
opcodeStack.pop_back();
|
||||||
|
if (t == EXOP_BRACKETL) break;
|
||||||
|
postfixStack.push_back(ExpressionPair(EXCOMM_OP,t));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (opcodeStack.empty() == false)
|
||||||
|
{
|
||||||
|
int CurrentPriority = ExpressionOpcodes[type].Priority;
|
||||||
|
while (!opcodeStack.empty())
|
||||||
|
{
|
||||||
|
ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1];
|
||||||
|
opcodeStack.pop_back();
|
||||||
|
|
||||||
|
if (t == EXOP_BRACKETL)
|
||||||
|
{
|
||||||
|
opcodeStack.push_back(t);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ExpressionOpcodes[t].Priority >= CurrentPriority)
|
||||||
|
{
|
||||||
|
postfixStack.push_back(ExpressionPair(EXCOMM_OP,t));
|
||||||
|
} else {
|
||||||
|
opcodeStack.push_back(t);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
opcodeStack.push_back(type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
infixPos += len;
|
||||||
|
lastOpcode = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!opcodeStack.empty())
|
||||||
|
{
|
||||||
|
ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1];
|
||||||
|
opcodeStack.pop_back();
|
||||||
|
|
||||||
|
if (t == EXOP_BRACKETL) // opening bracket without closing one
|
||||||
|
{
|
||||||
|
sprintf(expressionError,"Parenthesis not closed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
postfixStack.push_back(ExpressionPair(EXCOMM_OP,t));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// parse postfix now
|
||||||
|
int num = 0;
|
||||||
|
u32 opcode;
|
||||||
|
std::vector<u32> valueStack;
|
||||||
|
unsigned int arg[5];
|
||||||
|
|
||||||
|
while (num < postfixStack.size())
|
||||||
|
{
|
||||||
|
switch (postfixStack[num].first)
|
||||||
|
{
|
||||||
|
case EXCOMM_CONST: // konstante zahl
|
||||||
|
valueStack.push_back(postfixStack[num++].second);
|
||||||
|
break;
|
||||||
|
case EXCOMM_OP: // opcode
|
||||||
|
opcode = postfixStack[num++].second;
|
||||||
|
if (valueStack.size() < ExpressionOpcodes[opcode].args)
|
||||||
|
{
|
||||||
|
sprintf(expressionError,"Not enough arguments");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int l = 0; l < ExpressionOpcodes[opcode].args; l++)
|
||||||
|
{
|
||||||
|
arg[l] = valueStack[valueStack.size()-1];
|
||||||
|
valueStack.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (opcode)
|
||||||
|
{
|
||||||
|
case EXOP_SIGNPLUS: // keine aktion nötig
|
||||||
|
break;
|
||||||
|
case EXOP_SIGNMINUS: // -0
|
||||||
|
valueStack.push_back(0-arg[0]);
|
||||||
|
break;
|
||||||
|
case EXOP_BITNOT: // ~b
|
||||||
|
valueStack.push_back(~arg[0]);
|
||||||
|
break;
|
||||||
|
case EXOP_LOGNOT: // !b
|
||||||
|
valueStack.push_back(!arg[0]);
|
||||||
|
break;
|
||||||
|
case EXOP_MUL: // a*b
|
||||||
|
valueStack.push_back(arg[1]*arg[0]);
|
||||||
|
break;
|
||||||
|
case EXOP_DIV: // a/b
|
||||||
|
valueStack.push_back(arg[1]/arg[0]);
|
||||||
|
break;
|
||||||
|
case EXOP_MOD: // a%b
|
||||||
|
valueStack.push_back(arg[1]%arg[0]);
|
||||||
|
break;
|
||||||
|
case EXOP_ADD: // a+b
|
||||||
|
valueStack.push_back(arg[1]+arg[0]);
|
||||||
|
break;
|
||||||
|
case EXOP_SUB: // a-b
|
||||||
|
valueStack.push_back(arg[1]-arg[0]);
|
||||||
|
break;
|
||||||
|
case EXOP_SHL: // a<<b
|
||||||
|
valueStack.push_back(arg[1]<<arg[0]);
|
||||||
|
break;
|
||||||
|
case EXOP_SHR: // a>>b
|
||||||
|
valueStack.push_back(arg[1]>>arg[0]);
|
||||||
|
break;
|
||||||
|
case EXOP_GREATEREQUAL: // a >= b
|
||||||
|
valueStack.push_back(arg[1]>=arg[0]);
|
||||||
|
break;
|
||||||
|
case EXOP_GREATER: // a > b
|
||||||
|
valueStack.push_back(arg[1]>arg[0]);
|
||||||
|
break;
|
||||||
|
case EXOP_LOWEREQUAL: // a <= b
|
||||||
|
valueStack.push_back(arg[1]<=arg[0]);
|
||||||
|
break;
|
||||||
|
case EXOP_LOWER: // a < b
|
||||||
|
valueStack.push_back(arg[1]<arg[0]);
|
||||||
|
break;
|
||||||
|
case EXOP_EQUAL: // a == b
|
||||||
|
valueStack.push_back(arg[1]==arg[0]);
|
||||||
|
break;
|
||||||
|
case EXOP_NOTEQUAL: // a != b
|
||||||
|
valueStack.push_back(arg[1]!=arg[0]);
|
||||||
|
break;
|
||||||
|
case EXOP_BITAND: // a&b
|
||||||
|
valueStack.push_back(arg[1]&arg[0]);
|
||||||
|
break;
|
||||||
|
case EXOP_XOR: // a^b
|
||||||
|
valueStack.push_back(arg[1]^arg[0]);
|
||||||
|
break;
|
||||||
|
case EXOP_BITOR: // a|b
|
||||||
|
valueStack.push_back(arg[1]|arg[0]);
|
||||||
|
break;
|
||||||
|
case EXOP_LOGAND: // a && b
|
||||||
|
valueStack.push_back(arg[1]&&arg[0]);
|
||||||
|
break;
|
||||||
|
case EXOP_LOGOR: // a && b
|
||||||
|
valueStack.push_back(arg[1]||arg[0]);
|
||||||
|
break;
|
||||||
|
case EXOP_TERTIF: // darf so nicht vorkommen
|
||||||
|
return false;
|
||||||
|
case EXOP_TERTELSE: // exp ? exp : exp, else muss zuerst kommen!
|
||||||
|
if (postfixStack[num++].second != EXOP_TERTIF)
|
||||||
|
{
|
||||||
|
sprintf(expressionError,"Invalid tertiary operator");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
valueStack.push_back(arg[2]?arg[1]:arg[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valueStack.size() != 1) return false;
|
||||||
|
dest = valueStack[0];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayExpressionError(HWND hwnd)
|
||||||
|
{
|
||||||
|
if (expressionError[0] == 0)
|
||||||
|
{
|
||||||
|
MessageBox(hwnd,"Invalid expression","Invalid expression",MB_OK);
|
||||||
|
} else {
|
||||||
|
MessageBox(hwnd,expressionError,"Invalid expression",MB_OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool executeExpressionWindow(HWND hwnd, DebugInterface* cpu, u32& dest)
|
||||||
|
{
|
||||||
|
char expression[1024];
|
||||||
|
if (InputBox_GetString(GetModuleHandle(NULL), hwnd, "Expression", "",expression) == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parseExpression(expression,cpu,dest) == false)
|
||||||
|
{
|
||||||
|
displayExpressionError(hwnd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
8
Windows/Debugger/ExpressionParser.h
Normal file
8
Windows/Debugger/ExpressionParser.h
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../../Common/CommonTypes.h"
|
||||||
|
class DebugInterface;
|
||||||
|
|
||||||
|
bool executeExpressionWindow(HWND hwnd, DebugInterface* cpu, u32& dest);
|
||||||
|
void displayExpressionError(HWND hwnd);
|
||||||
|
bool parseExpression(char* exp, DebugInterface* cpu, u32& dest);
|
|
@ -266,6 +266,7 @@
|
||||||
<ClCompile Include="Debugger\Debugger_Disasm.cpp" />
|
<ClCompile Include="Debugger\Debugger_Disasm.cpp" />
|
||||||
<ClCompile Include="Debugger\Debugger_MemoryDlg.cpp" />
|
<ClCompile Include="Debugger\Debugger_MemoryDlg.cpp" />
|
||||||
<ClCompile Include="Debugger\Debugger_VFPUDlg.cpp" />
|
<ClCompile Include="Debugger\Debugger_VFPUDlg.cpp" />
|
||||||
|
<ClCompile Include="Debugger\ExpressionParser.cpp" />
|
||||||
<ClCompile Include="DinputDevice.cpp" />
|
<ClCompile Include="DinputDevice.cpp" />
|
||||||
<ClCompile Include="EmuThread.cpp" />
|
<ClCompile Include="EmuThread.cpp" />
|
||||||
<ClCompile Include="InputDevice.cpp" />
|
<ClCompile Include="InputDevice.cpp" />
|
||||||
|
@ -304,6 +305,7 @@
|
||||||
<ClInclude Include="Debugger\Debugger_Disasm.h" />
|
<ClInclude Include="Debugger\Debugger_Disasm.h" />
|
||||||
<ClInclude Include="Debugger\Debugger_MemoryDlg.h" />
|
<ClInclude Include="Debugger\Debugger_MemoryDlg.h" />
|
||||||
<ClInclude Include="Debugger\Debugger_VFPUDlg.h" />
|
<ClInclude Include="Debugger\Debugger_VFPUDlg.h" />
|
||||||
|
<ClInclude Include="Debugger\ExpressionParser.h" />
|
||||||
<ClInclude Include="DinputDevice.h" />
|
<ClInclude Include="DinputDevice.h" />
|
||||||
<ClInclude Include="EmuThread.h" />
|
<ClInclude Include="EmuThread.h" />
|
||||||
<ClInclude Include="InputDevice.h" />
|
<ClInclude Include="InputDevice.h" />
|
||||||
|
|
|
@ -101,6 +101,9 @@
|
||||||
<ClCompile Include="ControlMapping.cpp">
|
<ClCompile Include="ControlMapping.cpp">
|
||||||
<Filter>Windows\Input</Filter>
|
<Filter>Windows\Input</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="Debugger\ExpressionParser.cpp">
|
||||||
|
<Filter>Windows\Debugger</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Debugger\CtrlDisAsmView.h">
|
<ClInclude Include="Debugger\CtrlDisAsmView.h">
|
||||||
|
@ -179,6 +182,9 @@
|
||||||
<ClInclude Include="ControlMapping.h">
|
<ClInclude Include="ControlMapping.h">
|
||||||
<Filter>Windows\Input</Filter>
|
<Filter>Windows\Input</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Debugger\ExpressionParser.h">
|
||||||
|
<Filter>Windows\Debugger</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="icon1.ico">
|
<None Include="icon1.ico">
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue