From 3e255d7b98e94d110457dac0ddb8d3b998645e4c Mon Sep 17 00:00:00 2001 From: Kingcom Date: Tue, 13 Jan 2015 00:06:58 +0100 Subject: [PATCH] common: Add expression parser from ppsspp --- src/common/CMakeLists.txt | 2 + src/common/expression_parser.cpp | 593 +++++++++++++++++++++++++++++++ src/common/expression_parser.h | 30 ++ 3 files changed, 625 insertions(+) create mode 100644 src/common/expression_parser.cpp create mode 100644 src/common/expression_parser.h diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 3c3419bbc..7256369f7 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -4,6 +4,7 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in" "${CMAKE_CURRENT_SOU set(SRCS break_points.cpp emu_window.cpp + expression_parser.cpp extended_trace.cpp file_search.cpp file_util.cpp @@ -37,6 +38,7 @@ set(HEADERS cpu_detect.h debug_interface.h emu_window.h + expression_parser.h extended_trace.h fifo_queue.h file_search.h diff --git a/src/common/expression_parser.cpp b/src/common/expression_parser.cpp new file mode 100644 index 000000000..946898c58 --- /dev/null +++ b/src/common/expression_parser.cpp @@ -0,0 +1,593 @@ +#include "expression_parser.h" +#include +#include +#include + +typedef enum { + EXOP_BRACKETL, EXOP_BRACKETR, EXOP_MEML, EXOP_MEMR, EXOP_MEMSIZE, 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_MEM, EXOP_NONE, EXOP_COUNT +} ExpressionOpcodeType; + +typedef enum { EXCOMM_CONST, EXCOMM_CONST_FLOAT, EXCOMM_REF, EXCOMM_OP } ExpressionCommand; + +static char expressionError[256]; + +typedef struct { + char Name[4]; + unsigned char Priority; + unsigned char len; + unsigned char args; + bool sign; +} ExpressionOpcode; + +const ExpressionOpcode ExpressionOpcodes[] = { + { "(", 25, 1, 0, false }, // EXOP_BRACKETL + { ")", 25, 1, 0, false }, // EXOP_BRACKETR + { "[", 4, 1, 0, false }, // EXOP_MEML + { "]", 4, 1, 0, false }, // EXOP_MEMR + { ",", 5, 1, 2, false }, // EXOP_MEMSIZE + { "+", 22, 1, 1, true }, // EXOP_SIGNPLUS + { "-", 22, 1, 1, true }, // EXOP_SIGNMINUS + { "~", 22, 1, 1, false }, // EXOP_BITNOT + { "!", 22, 1, 1, false }, // EXOP_LOGNOT + { "*", 21, 1, 2, false }, // EXOP_MUL + { "/", 21, 1, 2, false }, // EXOP_DIV + { "%", 21, 1, 2, false }, // EXOP_MOD + { "+", 20, 1, 2, false }, // EXOP_ADD + { "-", 20, 1, 2, false }, // EXOP_SUB + { "<<", 19, 2, 2, false }, // EXOP_SHL + { ">>", 19, 2, 2, false }, // EXOP_SHR + { ">=", 18, 2, 2, false }, // EXOP_GREATEREQUAL + { ">", 18, 1, 2, false }, // EXOP_GREATER + { "<=", 18, 2, 2, false }, // EXOP_LOWEREQUAL + { "<", 18, 1, 2, false }, // EXOP_LOWER + { "==", 17, 2, 2, false }, // EXOP_EQUAL + { "!=", 17, 2, 2, false }, // EXOP_NOTEQUAL + { "&", 16, 1, 2, false }, // EXOP_BITAND + { "^", 15, 1, 2, false }, // EXOP_XOR + { "|", 14, 1, 2, false }, // EXOP_BITOR + { "&&", 13, 2, 2, false }, // EXOP_LOGAND + { "||", 12, 2, 2, false }, // EXOP_LOGOR + { "?", 10, 1, 0, false }, // EXOP_TERTIF + { ":", 11, 1, 3, false }, // EXOP_TERTELSE + { "", 0, 0, 0, false }, // EXOP_NUMBER + { "[]", 0, 0, 1, false }, // EXOP_MEM + { "", 0, 0, 0, false } // EXOP_NONE +}; + +bool parseNumber(char* str, int defaultrad, int len, uint32& 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' && defaultrad != 16) + { + 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; +} + +// Parse only a float, and return as float bits. +static bool parseFloat(const char *str, int len, uint32 &result) +{ + bool foundDecimal = false; + for (int i = 0; i < len; ++i) + { + if (str[i] == '.') + { + if (foundDecimal) + return false; + foundDecimal = true; + continue; + } + if (str[i] < '0' || str[i] > '9') + return false; + } + + float f = (float)atof(str); + memcpy(&result, &f, sizeof(result)); + return foundDecimal; +} + +ExpressionOpcodeType getExpressionOpcode(const 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 == '$' || c == '.') + { + return true; + } else { + return false; + } +} + +bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, PostfixExpression& dest) +{ + expressionError[0] = 0; + + int infixPos = 0; + int infixLen = (int)strlen(infix); + ExpressionOpcodeType lastOpcode = EXOP_NONE; + std::vector opcodeStack; + dest.clear(); + + while (infixPos < infixLen) + { + char first = tolower(infix[infixPos]); + char subStr[256]; + 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; + + uint32 value; + bool isFloat = false; + if (parseFloat(subStr,subPos,value) == true) + isFloat = true; + else if (parseNumber(subStr,16,subPos,value) == false) + { + sprintf(expressionError,"Invalid number \"%s\"",subStr); + return false; + } + + dest.push_back(ExpressionPair(isFloat?EXCOMM_CONST_FLOAT:EXCOMM_CONST,value)); + lastOpcode = EXOP_NUMBER; + } else if ((first >= 'a' && first <= 'z') || first == '@') + { + while (isAlphaNum(infix[infixPos])) + { + subStr[subPos++] = infix[infixPos++]; + } + subStr[subPos] = 0; + + uint32 value; + if (funcs->parseReference(subStr,value) == true) + { + dest.push_back(ExpressionPair(EXCOMM_REF,value)); + lastOpcode = EXOP_NUMBER; + continue; + } + + if (funcs->parseSymbol(subStr,value) == true) + { + dest.push_back(ExpressionPair(EXCOMM_CONST,value)); + lastOpcode = EXOP_NUMBER; + continue; + } + + sprintf(expressionError,"Invalid symbol \"%s\"",subStr); + return false; + } 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: + case EXOP_MEML: + 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; + dest.push_back(ExpressionPair(EXCOMM_OP,t)); + } + break; + case EXOP_MEMR: + while (true) + { + if (opcodeStack.empty()) + { + sprintf(expressionError,"Closing bracket without opening one"); + return false; + } + ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1]; + opcodeStack.pop_back(); + if (t == EXOP_MEML) + { + dest.push_back(ExpressionPair(EXCOMM_OP,EXOP_MEM)); + break; + } + dest.push_back(ExpressionPair(EXCOMM_OP,t)); + } + type = EXOP_NUMBER; + 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 || t == EXOP_MEML) + { + opcodeStack.push_back(t); + break; + } + + if (ExpressionOpcodes[t].Priority >= CurrentPriority) + { + dest.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; + } + dest.push_back(ExpressionPair(EXCOMM_OP,t)); + } + +#if 0 // only for testing + char test[1024]; + int testPos = 0; + for (int i = 0; i < dest.size(); i++) + { + switch (dest[i].first) + { + case EXCOMM_CONST: + case EXCOMM_CONST_FLOAT: + testPos += sprintf(&test[testPos],"0x%04X ",dest[i].second); + break; + case EXCOMM_REF: + testPos += sprintf(&test[testPos],"r%d ",dest[i].second); + break; + case EXCOMM_OP: + testPos += sprintf(&test[testPos],"%s ",ExpressionOpcodes[dest[i].second].Name); + break; + }; + } +#endif + + return true; +} + +bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs, uint32& dest) +{ + size_t num = 0; + uint32 opcode; + std::vector valueStack; + unsigned int arg[5]; + float fArg[5]; + bool useFloat = false; + + while (num < exp.size()) + { + switch (exp[num].first) + { + case EXCOMM_CONST: // konstante zahl + valueStack.push_back(exp[num++].second); + break; + case EXCOMM_CONST_FLOAT: + useFloat = true; + valueStack.push_back(exp[num++].second); + break; + case EXCOMM_REF: + useFloat = useFloat || funcs->getReferenceType(exp[num].second) == EXPR_TYPE_FLOAT; + opcode = funcs->getReferenceValue(exp[num++].second); + valueStack.push_back(opcode); + break; + case EXCOMM_OP: // opcode + opcode = exp[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(); + } + // In case of float representation. + memcpy(fArg, arg, sizeof(fArg)); + + switch (opcode) + { + case EXOP_MEMSIZE: // must be followed by EXOP_MEM + if (exp[num++].second != EXOP_MEM) + { + sprintf(expressionError,"Invalid memsize operator"); + return false; + } + + uint32 val; + if(funcs->getMemoryValue(arg[1],arg[0],val,expressionError) == false) + { + return false; + } + valueStack.push_back(val); + break; + case EXOP_MEM: + { + uint32 val; + if (funcs->getMemoryValue(arg[0],4,val,expressionError) == false) + { + return false; + } + valueStack.push_back(val); + } + break; + case EXOP_SIGNPLUS: // keine aktion nötig + break; + case EXOP_SIGNMINUS: // -0 + if (useFloat) + valueStack.push_back(0.0-fArg[0]); + else + 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 + if (useFloat) + valueStack.push_back(fArg[1]*fArg[0]); + else + valueStack.push_back(arg[1]*arg[0]); + break; + case EXOP_DIV: // a/b + if (arg[0] == 0) + { + sprintf(expressionError,"Division by zero"); + return false; + } + if (useFloat) + valueStack.push_back(fArg[1]/fArg[0]); + else + valueStack.push_back(arg[1]/arg[0]); + break; + case EXOP_MOD: // a%b + if (arg[0] == 0) + { + sprintf(expressionError,"Modulo by zero"); + return false; + } + valueStack.push_back(arg[1]%arg[0]); + break; + case EXOP_ADD: // a+b + if (useFloat) + valueStack.push_back(fArg[1]+fArg[0]); + else + valueStack.push_back(arg[1]+arg[0]); + break; + case EXOP_SUB: // a-b + if (useFloat) + valueStack.push_back(fArg[1]-fArg[0]); + else + valueStack.push_back(arg[1]-arg[0]); + break; + case EXOP_SHL: // a<>b + valueStack.push_back(arg[1]>>arg[0]); + break; + case EXOP_GREATEREQUAL: // a >= b + if (useFloat) + valueStack.push_back(fArg[1]>=fArg[0]); + else + valueStack.push_back(arg[1]>=arg[0]); + break; + case EXOP_GREATER: // a > b + if (useFloat) + valueStack.push_back(fArg[1]>fArg[0]); + else + valueStack.push_back(arg[1]>arg[0]); + break; + case EXOP_LOWEREQUAL: // a <= b + if (useFloat) + valueStack.push_back(fArg[1]<=fArg[0]); + else + valueStack.push_back(arg[1]<=arg[0]); + break; + case EXOP_LOWER: // a < b + if (useFloat) + valueStack.push_back(fArg[1] + +typedef u32 uint32; + +typedef std::pair ExpressionPair; +typedef std::vector PostfixExpression; + +enum ExpressionType +{ + EXPR_TYPE_UINT = 0, + EXPR_TYPE_FLOAT = 2, +}; + +class IExpressionFunctions +{ +public: + virtual bool parseReference(char* str, uint32& referenceIndex) = 0; + virtual bool parseSymbol(char* str, uint32& symbolValue) = 0; + virtual uint32 getReferenceValue(uint32 referenceIndex) = 0; + virtual ExpressionType getReferenceType(uint32 referenceIndex) = 0; + virtual bool getMemoryValue(uint32 address, int size, uint32& dest, char* error) = 0; +}; + +bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, PostfixExpression& dest); +bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs, uint32& dest); +bool parseExpression(const char* exp, IExpressionFunctions* funcs, uint32& dest); +const char* getExpressionError();