This commit is contained in:
parent
4be05b5974
commit
a0be994c5a
|
|
@ -27,19 +27,15 @@ x64).</P>
|
|||
registers (of all sizes) can be used as variables.</P>
|
||||
<P class=rvps3><U>memory locations</U>: You can read from a memory location by using one of the
|
||||
following expressions:<BR>[addr] - read a
|
||||
DWORD/QWORD, depending on the architecture.<BR>@addr - same as
|
||||
above.<BR><EM>n</EM>:[addr] - read <EM>n</EM> bytes.<BR>
|
||||
@<EM>n</EM>:addr - same as
|
||||
above.<BR><STRONG>REMARKS</STRONG>:<BR>- <EM>n</EM> is the amount of bytes to
|
||||
read, this can be anything smaller than 4 on x32 and smaller than 8 on x64 when
|
||||
specified, otherwise there will be an error.<BR>- addr is directly interpreted
|
||||
as a value, when you want to read [addr+1] you should use
|
||||
brackets:<BR>
|
||||
DWORD/QWORD, depending on the
|
||||
architecture.<BR><EM>n</EM>:[addr] - read <EM>n</EM> bytes
|
||||
from.<BR><STRONG>REMARKS</STRONG>:<BR>- <EM>n</EM> is the amount of bytes to read, this can be anything
|
||||
smaller than 4 on x32 and smaller than 8 on x64 when specified, otherwise
|
||||
|
||||
|
||||
|
||||
|
||||
@(addr+1), @addr+1 will read: [addr]+1.</P>
|
||||
there will be an error.</P>
|
||||
<P class=rvps3><U>flags</U>: Debug
|
||||
flags (interpreted as integer) can be used as input. Flags are prefixed with a
|
||||
'!' following the flag name. Valid flags are: !cf, !pf, !af, !zf, !sf, !tf, !if,
|
||||
|
|
@ -75,7 +71,7 @@ used.</DIV><U> </U>
|
|||
"oep" or "ep" the address of these will be returned
|
||||
instead.<BR><BR><STRONG>Notice</STRONG>: Instead of the ':' delimiter you can
|
||||
also use a '.' If you need to query module information such as
|
||||
"[module]:imagebase" or "[module]":entry" you are adviced to
|
||||
"[module]:imagebase" or "[module]":entry" you are advised to
|
||||
use a '?' as delimiter instead ("[module]?entry"). The '?' does
|
||||
checking for named exports later, so it will still work when there is an
|
||||
export called "entry" in the module.</LI></OL>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include <shlwapi.h>
|
||||
#include <stdarg.h>
|
||||
#include <vector>
|
||||
#include <stack>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
|
|
|
|||
|
|
@ -268,6 +268,32 @@ static bool isvalidexpression(const char* expression)
|
|||
return valfromstring(expression, &value);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Check if a character is a mathematical operator. Used to determine stuff like "a *= b"
|
||||
\param ch The character to check.
|
||||
\return true if the character is an operator, false otherwise.
|
||||
*/
|
||||
static bool mathisoperator(const char ch)
|
||||
{
|
||||
switch(ch)
|
||||
{
|
||||
case '*':
|
||||
case '`':
|
||||
case '/':
|
||||
case '%':
|
||||
case '+':
|
||||
case '-':
|
||||
case '<':
|
||||
case '>':
|
||||
case '&':
|
||||
case '^':
|
||||
case '|':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Special formats a given command. Used as a little hack to support stuff like 'x++' and 'x=y'
|
||||
\param [in,out] string String to format.
|
||||
|
|
@ -300,7 +326,7 @@ static void specialformat(char* string)
|
|||
sprintf(str, "%s%c1", found, op);
|
||||
strcpy(found, str);
|
||||
}
|
||||
if(mathisoperator(*a) > 2) //x*=3 -> x=x*3
|
||||
if(mathisoperator(*a)) //x*=3 -> x=x*3
|
||||
{
|
||||
char op = *a;
|
||||
*a = 0;
|
||||
|
|
@ -350,8 +376,6 @@ COMMAND* cmdfindmain(COMMAND* cmd_list, char* command)
|
|||
specialformat(command);
|
||||
cmd = cmdget(cmd_list, command);
|
||||
}
|
||||
if(!cmd or !cmd->cbCommand)
|
||||
mathformat(command);
|
||||
return cmd;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,469 @@
|
|||
#include "expressionparser.h"
|
||||
#include "value.h"
|
||||
|
||||
ExpressionParser::Token::Token(const String & data, const Type type)
|
||||
{
|
||||
_data = data;
|
||||
_type = type;
|
||||
}
|
||||
|
||||
const String ExpressionParser::Token::data() const
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
const ExpressionParser::Token::Type ExpressionParser::Token::type() const
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
|
||||
const ExpressionParser::Token::Associativity ExpressionParser::Token::associativity() const
|
||||
{
|
||||
switch(_type)
|
||||
{
|
||||
case Type::OperatorUnarySub:
|
||||
case Type::OperatorNot:
|
||||
return Associativity::RightToLeft;
|
||||
case Type::OperatorMul:
|
||||
case Type::OperatorHiMul:
|
||||
case Type::OperatorDiv:
|
||||
case Type::OperatorMod:
|
||||
case Type::OperatorAdd:
|
||||
case Type::OperatorSub:
|
||||
case Type::OperatorShl:
|
||||
case Type::OperatorShr:
|
||||
case Type::OperatorAnd:
|
||||
case Type::OperatorXor:
|
||||
case Type::OperatorOr:
|
||||
return Associativity::LeftToRight;
|
||||
default:
|
||||
return Associativity::Unspecified;
|
||||
}
|
||||
}
|
||||
|
||||
const int ExpressionParser::Token::precedence() const
|
||||
{
|
||||
switch(_type)
|
||||
{
|
||||
case Type::OperatorUnarySub:
|
||||
case Type::OperatorNot:
|
||||
return 7;
|
||||
case Type::OperatorMul:
|
||||
case Type::OperatorHiMul:
|
||||
case Type::OperatorDiv:
|
||||
case Type::OperatorMod:
|
||||
return 6;
|
||||
case Type::OperatorAdd:
|
||||
case Type::OperatorSub:
|
||||
return 5;
|
||||
case Type::OperatorShl:
|
||||
case Type::OperatorShr:
|
||||
return 4;
|
||||
case Type::OperatorAnd:
|
||||
return 3;
|
||||
case Type::OperatorXor:
|
||||
return 2;
|
||||
case Type::OperatorOr:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const bool ExpressionParser::Token::isOperator() const
|
||||
{
|
||||
return _type != Type::Data && _type != Type::OpenBracket && _type != Type::CloseBracket;
|
||||
}
|
||||
|
||||
ExpressionParser::ExpressionParser(const String & expression)
|
||||
{
|
||||
tokenize(fixClosingBrackets(expression));
|
||||
shuntingYard();
|
||||
}
|
||||
|
||||
String ExpressionParser::fixClosingBrackets(const String & expression)
|
||||
{
|
||||
int open = 0;
|
||||
int close = 0;
|
||||
size_t len = expression.length();
|
||||
for(size_t i = 0; i < len; i++)
|
||||
{
|
||||
if(expression[i] == '(')
|
||||
open++;
|
||||
else if(expression[i] == ')')
|
||||
close++;
|
||||
}
|
||||
String result = expression;
|
||||
if(close < open)
|
||||
{
|
||||
for(int i = 0; i < open - close; i++)
|
||||
result += ")";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void ExpressionParser::tokenize(const String & expression)
|
||||
{
|
||||
bool stateMemory = false;
|
||||
size_t len = expression.length();
|
||||
for(size_t i = 0; i < len; i++)
|
||||
{
|
||||
char ch = expression[i];
|
||||
switch(ch)
|
||||
{
|
||||
case '[':
|
||||
{
|
||||
stateMemory = true;
|
||||
_curToken += ch;
|
||||
}
|
||||
break;
|
||||
|
||||
case ']':
|
||||
{
|
||||
stateMemory = false;
|
||||
_curToken += ch;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
if(stateMemory)
|
||||
_curToken += ch;
|
||||
else
|
||||
{
|
||||
switch(ch)
|
||||
{
|
||||
case '(':
|
||||
addOperatorToken(ch, Token::Type::OpenBracket);
|
||||
break;
|
||||
case ')':
|
||||
addOperatorToken(ch, Token::Type::CloseBracket);
|
||||
break;
|
||||
case '~':
|
||||
addOperatorToken(ch, Token::Type::OperatorNot);
|
||||
break;
|
||||
case '*':
|
||||
addOperatorToken(ch, Token::Type::OperatorMul);
|
||||
break;
|
||||
case '`':
|
||||
addOperatorToken(ch, Token::Type::OperatorHiMul);
|
||||
break;
|
||||
case '/':
|
||||
addOperatorToken(ch, Token::Type::OperatorDiv);
|
||||
break;
|
||||
case '%':
|
||||
addOperatorToken(ch, Token::Type::OperatorMod);
|
||||
break;
|
||||
case '+':
|
||||
if(!isUnaryOperator()) //skip all unary add operators
|
||||
addOperatorToken(ch, Token::Type::OperatorAdd);
|
||||
break;
|
||||
case '-':
|
||||
if(isUnaryOperator())
|
||||
addOperatorToken(ch, Token::Type::OperatorUnarySub);
|
||||
else
|
||||
addOperatorToken(ch, Token::Type::OperatorSub);
|
||||
break;
|
||||
case '<':
|
||||
addOperatorToken(ch, Token::Type::OperatorShl);
|
||||
break;
|
||||
case '>':
|
||||
addOperatorToken(ch, Token::Type::OperatorShr);
|
||||
break;
|
||||
case '&':
|
||||
addOperatorToken(ch, Token::Type::OperatorAnd);
|
||||
break;
|
||||
case '^':
|
||||
addOperatorToken(ch, Token::Type::OperatorXor);
|
||||
break;
|
||||
case '|':
|
||||
addOperatorToken(ch, Token::Type::OperatorOr);
|
||||
break;
|
||||
case ' ': //ignore spaces
|
||||
break;
|
||||
default:
|
||||
_curToken += ch;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(_curToken.length() != 0) //make sure the last token is added
|
||||
_tokens.push_back(Token(_curToken, Token::Type::Data));
|
||||
}
|
||||
|
||||
void ExpressionParser::addOperatorToken(const char ch, const Token::Type type)
|
||||
{
|
||||
if(_curToken.length()) //add a new data token when there is data in the buffer
|
||||
{
|
||||
_tokens.push_back(Token(_curToken, Token::Type::Data));
|
||||
_curToken = "";
|
||||
}
|
||||
String data;
|
||||
data += ch;
|
||||
_tokens.push_back(Token(data, type)); //add the operator token
|
||||
}
|
||||
|
||||
bool ExpressionParser::isUnaryOperator()
|
||||
{
|
||||
if(_curToken.length()) //data before the operator means it is no unary operator
|
||||
return false;
|
||||
if(!_tokens.size()) //no tokens before the operator means it is an unary operator
|
||||
return true;
|
||||
Token lastToken = _tokens[_tokens.size() - 1];
|
||||
return lastToken.isOperator(); //if the previous operator is a token, the operator is an unary operator
|
||||
}
|
||||
|
||||
void ExpressionParser::shuntingYard()
|
||||
{
|
||||
//Implementation of Dijkstra's Shunting-yard algorithm
|
||||
std::vector<Token> queue;
|
||||
std::stack<Token> stack;
|
||||
size_t len = _tokens.size();
|
||||
//process the tokens
|
||||
for(size_t i = 0; i < len; i++)
|
||||
{
|
||||
Token & token = _tokens[i];
|
||||
switch(token.type())
|
||||
{
|
||||
case Token::Type::Data:
|
||||
queue.push_back(token);
|
||||
break;
|
||||
case Token::Type::OpenBracket:
|
||||
stack.push(token);
|
||||
break;
|
||||
case Token::Type::CloseBracket:
|
||||
while(true)
|
||||
{
|
||||
if(stack.empty()) //empty stack = bracket mismatch
|
||||
return;
|
||||
Token curToken = stack.top();
|
||||
stack.pop();
|
||||
if(curToken.type() == Token::Type::OpenBracket)
|
||||
break;
|
||||
queue.push_back(curToken);
|
||||
}
|
||||
break;
|
||||
default: //operator
|
||||
Token & o1 = token;
|
||||
while(!stack.empty())
|
||||
{
|
||||
Token o2 = stack.top();
|
||||
if(o2.isOperator() &&
|
||||
(o1.associativity() == Token::Associativity::LeftToRight && o1.precedence() <= o2.precedence()) ||
|
||||
(o1.associativity() == Token::Associativity::RightToLeft && o1.precedence() < o2.precedence()))
|
||||
{
|
||||
queue.push_back(o2);
|
||||
stack.pop();
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
stack.push(o1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//pop the remaining operators
|
||||
while(!stack.empty())
|
||||
{
|
||||
Token curToken = stack.top();
|
||||
stack.pop();
|
||||
if(curToken.type() == Token::Type::OpenBracket || curToken.type() == Token::Type::CloseBracket) //brackets on the stack means invalid expression
|
||||
return;
|
||||
queue.push_back(curToken);
|
||||
}
|
||||
_prefixTokens = queue;
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
#include <intrin.h>
|
||||
|
||||
static inline unsigned long long umulhi(unsigned long long x, unsigned long long y)
|
||||
{
|
||||
unsigned __int64 res;
|
||||
_umul128(x, y, &res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline long long mulhi(long long x, long long y)
|
||||
{
|
||||
__int64 res;
|
||||
_mul128(x, y, &res);
|
||||
return res;
|
||||
}
|
||||
#else
|
||||
static inline unsigned int umulhi(unsigned int x, unsigned int y)
|
||||
{
|
||||
return (unsigned int)(((unsigned long long)x * y) >> 32);
|
||||
}
|
||||
|
||||
static inline int mulhi(int x, int y)
|
||||
{
|
||||
return (int)(((long long)x * y) >> 32);
|
||||
}
|
||||
#endif //__MINGW64__
|
||||
|
||||
template<typename T>
|
||||
static bool operation(const ExpressionParser::Token::Type type, const T op1, const T op2, T & result)
|
||||
{
|
||||
result = 0;
|
||||
switch(type)
|
||||
{
|
||||
case ExpressionParser::Token::Type::OperatorUnarySub:
|
||||
result = op1 * ~0;
|
||||
return true;
|
||||
case ExpressionParser::Token::Type::OperatorNot:
|
||||
result = ~op1;
|
||||
return true;
|
||||
case ExpressionParser::Token::Type::OperatorMul:
|
||||
result = op1 * op2;
|
||||
return true;
|
||||
case ExpressionParser::Token::Type::OperatorHiMul:
|
||||
result = umulhi(op1, op2);
|
||||
return true;
|
||||
case ExpressionParser::Token::Type::OperatorDiv:
|
||||
if(op2 != 0)
|
||||
{
|
||||
result = op1 / op2;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case ExpressionParser::Token::Type::OperatorMod:
|
||||
if(op2 != 0)
|
||||
{
|
||||
result = op1 % op2;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case ExpressionParser::Token::Type::OperatorAdd:
|
||||
result = op1 + op2;
|
||||
return true;
|
||||
case ExpressionParser::Token::Type::OperatorSub:
|
||||
result = op1 - op2;
|
||||
return true;
|
||||
case ExpressionParser::Token::Type::OperatorShl:
|
||||
result = op1 << op2;
|
||||
return true;
|
||||
case ExpressionParser::Token::Type::OperatorShr:
|
||||
result = op1 >> op2;
|
||||
return true;
|
||||
case ExpressionParser::Token::Type::OperatorAnd:
|
||||
result = op1 & op2;
|
||||
return true;
|
||||
case ExpressionParser::Token::Type::OperatorXor:
|
||||
result = op1 ^ op2;
|
||||
return true;
|
||||
case ExpressionParser::Token::Type::OperatorOr:
|
||||
result = op1 | op2;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ExpressionParser::unsignedoperation(const Token::Type type, const uint op1, const uint op2, uint & result)
|
||||
{
|
||||
if(type == Token::Type::OperatorHiMul)
|
||||
{
|
||||
result = umulhi(op1, op2);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return operation<uint>(type, op1, op2, result);
|
||||
}
|
||||
|
||||
bool ExpressionParser::signedoperation(const Token::Type type, const sint op1, const sint op2, uint & result)
|
||||
{
|
||||
if(type == Token::Type::OperatorHiMul)
|
||||
{
|
||||
result = mulhi(op1, op2);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
sint signedResult;
|
||||
if(!operation<sint>(type, op1, op2, signedResult))
|
||||
return false;
|
||||
result = (uint)signedResult;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool ExpressionParser::valFromString(const String & data, uint & value)
|
||||
{
|
||||
return sscanf_s(data.c_str(), "%u", &value) == 1;
|
||||
}
|
||||
|
||||
bool ExpressionParser::calculate(uint & value, bool signedcalc, bool silent, bool baseonly, int* value_size, bool* isvar, bool* hexonly)
|
||||
{
|
||||
value = 0;
|
||||
if(!_prefixTokens.size())
|
||||
return false;
|
||||
std::stack<uint> stack;
|
||||
size_t len = _prefixTokens.size();
|
||||
//calculate the result from the RPN queue
|
||||
for(size_t i = 0; i < len; i++)
|
||||
{
|
||||
Token & token = _prefixTokens[i];
|
||||
if(token.isOperator())
|
||||
{
|
||||
uint op1 = 0;
|
||||
uint op2 = 0;
|
||||
uint result = 0;
|
||||
switch(token.type())
|
||||
{
|
||||
case Token::Type::OperatorUnarySub:
|
||||
case Token::Type::OperatorNot:
|
||||
if(stack.size() < 1)
|
||||
return false;
|
||||
op1 = stack.top();
|
||||
stack.pop();
|
||||
if(signedcalc)
|
||||
signedoperation(token.type(), op1, op2, result);
|
||||
else
|
||||
unsignedoperation(token.type(), op1, op2, result);
|
||||
stack.push(result);
|
||||
break;
|
||||
case Token::Type::OperatorMul:
|
||||
case Token::Type::OperatorHiMul:
|
||||
case Token::Type::OperatorDiv:
|
||||
case Token::Type::OperatorMod:
|
||||
case Token::Type::OperatorAdd:
|
||||
case Token::Type::OperatorSub:
|
||||
case Token::Type::OperatorShl:
|
||||
case Token::Type::OperatorShr:
|
||||
case Token::Type::OperatorAnd:
|
||||
case Token::Type::OperatorXor:
|
||||
case Token::Type::OperatorOr:
|
||||
if(stack.size() < 2)
|
||||
return false;
|
||||
op2 = stack.top();
|
||||
stack.pop();
|
||||
op1 = stack.top();
|
||||
stack.pop();
|
||||
if(signedcalc)
|
||||
signedoperation(token.type(), op1, op2, result);
|
||||
else
|
||||
unsignedoperation(token.type(), op1, op2, result);
|
||||
stack.push(result);
|
||||
break;
|
||||
default: //do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint result;
|
||||
if(!valfromstring_noexpr(token.data().c_str(), &result, silent, baseonly, value_size, isvar, hexonly))
|
||||
return false;
|
||||
stack.push(result);
|
||||
}
|
||||
|
||||
}
|
||||
if(stack.empty()) //empty result stack means error
|
||||
return false;
|
||||
value = stack.top();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
#ifndef _EXPRESSION_PARSER_H
|
||||
#define _EXPRESSION_PARSER_H
|
||||
|
||||
#include "_global.h"
|
||||
|
||||
class ExpressionParser
|
||||
{
|
||||
public:
|
||||
ExpressionParser(const String & expression);
|
||||
bool calculate(uint & value, bool signedcalc, bool silent, bool baseonly, int* value_size, bool* isvar, bool* hexonly);
|
||||
|
||||
class Token
|
||||
{
|
||||
public:
|
||||
enum class Type
|
||||
{
|
||||
Data,
|
||||
OpenBracket,
|
||||
CloseBracket,
|
||||
OperatorUnarySub,
|
||||
OperatorNot,
|
||||
OperatorMul,
|
||||
OperatorHiMul,
|
||||
OperatorDiv,
|
||||
OperatorMod,
|
||||
OperatorAdd,
|
||||
OperatorSub,
|
||||
OperatorShl,
|
||||
OperatorShr,
|
||||
OperatorAnd,
|
||||
OperatorXor,
|
||||
OperatorOr
|
||||
};
|
||||
|
||||
enum class Associativity
|
||||
{
|
||||
LeftToRight,
|
||||
RightToLeft,
|
||||
Unspecified
|
||||
};
|
||||
|
||||
Token(const String & data, const Type type);
|
||||
const String data() const;
|
||||
const Type type() const;
|
||||
const Associativity associativity() const;
|
||||
const int precedence() const;
|
||||
const bool isOperator() const;
|
||||
|
||||
private:
|
||||
String _data;
|
||||
Type _type;
|
||||
};
|
||||
|
||||
private:
|
||||
String fixClosingBrackets(const String & expression);
|
||||
bool isUnaryOperator();
|
||||
void tokenize(const String & expression);
|
||||
void shuntingYard();
|
||||
void addOperatorToken(const char ch, const Token::Type type);
|
||||
bool unsignedoperation(const Token::Type type, const uint op1, const uint op2, uint & result);
|
||||
bool signedoperation(const Token::Type type, const sint op1, const sint op2, uint & result);
|
||||
bool valFromString(const String & data, uint & value);
|
||||
|
||||
std::vector<Token> _tokens;
|
||||
std::vector<Token> _prefixTokens;
|
||||
String _curToken;
|
||||
};
|
||||
|
||||
#endif //_EXPRESSION_PARSER_H
|
||||
|
|
@ -1,520 +0,0 @@
|
|||
/**
|
||||
@file math.cpp
|
||||
|
||||
@brief Implements various functionalities that have to do with handling expression text.
|
||||
*/
|
||||
|
||||
#include "math.h"
|
||||
#include "value.h"
|
||||
|
||||
/**
|
||||
\brief A bracket pair. This structure describes a piece of brackets '(' and ')'
|
||||
*/
|
||||
struct BRACKET_PAIR
|
||||
{
|
||||
/**
|
||||
\brief The position in the string of the opening bracket '('.
|
||||
*/
|
||||
int openpos;
|
||||
|
||||
/**
|
||||
\brief The position in the string of the closing bracket ')'.
|
||||
*/
|
||||
int closepos;
|
||||
|
||||
/**
|
||||
\brief The depth of the pair (for example when you have "((1+4)*4)" the second '(' has layer 2).
|
||||
*/
|
||||
int layer;
|
||||
|
||||
/**
|
||||
\brief 0 when there is nothing set, 1 when the openpos is set, 2 when everything is set (aka pair is complete).
|
||||
*/
|
||||
int isset;
|
||||
};
|
||||
|
||||
/**
|
||||
\brief An expression. This structure describes an expression in form of bracket pairs.
|
||||
*/
|
||||
struct EXPRESSION
|
||||
{
|
||||
/**
|
||||
\brief The bracket pairs.
|
||||
*/
|
||||
BRACKET_PAIR* pairs;
|
||||
|
||||
/**
|
||||
\brief The total number of bracket pairs.
|
||||
*/
|
||||
int total_pairs;
|
||||
|
||||
/**
|
||||
\brief The expression text everything is derived from.
|
||||
*/
|
||||
const char* expression;
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Determines if a characters is an operator.
|
||||
\param ch The character to check.
|
||||
\return The number of the operator. 0 when the character is no operator. Otherwise it returns one of the following numbers:
|
||||
|
||||
- 1 ( )
|
||||
- 2 ~ (NOT)
|
||||
- 3 * / % (MUL DIV)
|
||||
- 4 + - (ADD SUB)
|
||||
- 5 < > (SHL SHR)
|
||||
- 6 & (AND)
|
||||
- 7 ^ (XOR)
|
||||
- 8 | (OR)
|
||||
*/
|
||||
int mathisoperator(char ch)
|
||||
{
|
||||
if(ch == '(' or ch == ')')
|
||||
return 1;
|
||||
else if(ch == '~')
|
||||
return 2;
|
||||
else if(ch == '*' or ch == '`' or ch == '/' or ch == '%')
|
||||
return 3;
|
||||
else if(ch == '+' or ch == '-')
|
||||
return 4;
|
||||
else if(ch == '<' or ch == '>')
|
||||
return 5;
|
||||
else if(ch == '&')
|
||||
return 6;
|
||||
else if(ch == '^')
|
||||
return 7;
|
||||
else if(ch == '|')
|
||||
return 8;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Formats the given text. It removes double operators like "**" and "||"
|
||||
\param [in,out] text The text to format.
|
||||
*/
|
||||
void mathformat(char* text)
|
||||
{
|
||||
int len = (int)strlen(text);
|
||||
Memory<char*> temp(len + 1, "mathformat:temp");
|
||||
memset(temp, 0, len + 1);
|
||||
for(int i = 0, j = 0; i < len; i++)
|
||||
if(mathisoperator(text[i]) < 3 or text[i] != text[i + 1])
|
||||
j += sprintf(temp + j, "%c", text[i]);
|
||||
strcpy(text, temp);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Checks if the given text contains operators.
|
||||
\param text The text to check.
|
||||
\return true if the text contains operator, false if not.
|
||||
*/
|
||||
bool mathcontains(const char* text)
|
||||
{
|
||||
if(*text == '-') //ignore negative values
|
||||
text++;
|
||||
int len = (int)strlen(text);
|
||||
for(int i = 0; i < len; i++)
|
||||
if(mathisoperator(text[i]))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef __MINGW64__
|
||||
static inline unsigned long long umulhi(unsigned long long x, unsigned long long y)
|
||||
{
|
||||
return (unsigned long long)(((__uint128_t)x * y) >> 64);
|
||||
}
|
||||
|
||||
static inline long long mulhi(long long x, long long y)
|
||||
{
|
||||
return (long long)(((__int128_t)x * y) >> 64);
|
||||
}
|
||||
#elif _WIN64
|
||||
#include <intrin.h>
|
||||
static inline unsigned long long umulhi(unsigned long long x, unsigned long long y)
|
||||
{
|
||||
unsigned __int64 res;
|
||||
_umul128(x, y, &res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline long long mulhi(long long x, long long y)
|
||||
{
|
||||
__int64 res;
|
||||
_mul128(x, y, &res);
|
||||
return res;
|
||||
}
|
||||
#else
|
||||
static inline unsigned int umulhi(unsigned int x, unsigned int y)
|
||||
{
|
||||
return (unsigned int)(((unsigned long long)x * y) >> 32);
|
||||
}
|
||||
|
||||
static inline int mulhi(int x, int y)
|
||||
{
|
||||
return (int)(((long long)x * y) >> 32);
|
||||
}
|
||||
#endif //__MINGW64__
|
||||
|
||||
/**
|
||||
\brief Do an operation on two unsigned numbers.
|
||||
\param op The operation to do (this must be a valid operator).
|
||||
\param left The number left of the operator.
|
||||
\param right The number right of the operator.
|
||||
\param [out] result The result of the operator. Cannot be null.
|
||||
\return true if the operation succeeded. It could fail on zero devision or an invalid operator.
|
||||
*/
|
||||
bool mathdounsignedoperation(char op, uint left, uint right, uint* result)
|
||||
{
|
||||
switch(op)
|
||||
{
|
||||
case '*':
|
||||
*result = left * right;
|
||||
return true;
|
||||
case '`':
|
||||
*result = umulhi(left, right);
|
||||
return true;
|
||||
case '/':
|
||||
if(right)
|
||||
{
|
||||
*result = left / right;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case '%':
|
||||
if(right)
|
||||
{
|
||||
*result = left % right;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case '+':
|
||||
*result = left + right;
|
||||
return true;
|
||||
case '-':
|
||||
*result = left - right;
|
||||
return true;
|
||||
case '<':
|
||||
*result = left << right;
|
||||
return true;
|
||||
case '>':
|
||||
*result = left >> right;
|
||||
return true;
|
||||
case '&':
|
||||
*result = left & right;
|
||||
return true;
|
||||
case '^':
|
||||
*result = left ^ right;
|
||||
return true;
|
||||
case '|':
|
||||
*result = left | right;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Do an operation on two signed numbers.
|
||||
\param op The operation to do (this must be a valid operator).
|
||||
\param left The number left of the operator.
|
||||
\param right The number right of the operator.
|
||||
\param [out] result The result of the operator. Cannot be null.
|
||||
\return true if the operation succeeded. It could fail on zero devision or an invalid operator.
|
||||
*/
|
||||
bool mathdosignedoperation(char op, sint left, sint right, sint* result)
|
||||
{
|
||||
switch(op)
|
||||
{
|
||||
case '*':
|
||||
*result = left * right;
|
||||
return true;
|
||||
case '`':
|
||||
*result = mulhi(left, right);
|
||||
return true;
|
||||
case '/':
|
||||
if(right)
|
||||
{
|
||||
*result = left / right;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case '%':
|
||||
if(right)
|
||||
{
|
||||
*result = left % right;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case '+':
|
||||
*result = left + right;
|
||||
return true;
|
||||
case '-':
|
||||
*result = left - right;
|
||||
return true;
|
||||
case '<':
|
||||
*result = left << right;
|
||||
return true;
|
||||
case '>':
|
||||
*result = left >> right;
|
||||
return true;
|
||||
case '&':
|
||||
*result = left & right;
|
||||
return true;
|
||||
case '^':
|
||||
*result = left ^ right;
|
||||
return true;
|
||||
case '|':
|
||||
*result = left | right;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Fills a BRACKET_PAIR structure.
|
||||
\param [in,out] expstruct The expression structure. Cannot be null.
|
||||
\param pos The position to fill, position of '(' or ')'.
|
||||
\param layer The layer this bracket is in.
|
||||
*/
|
||||
static void fillpair(EXPRESSION* expstruct, int pos, int layer)
|
||||
{
|
||||
for(int i = 0; i < expstruct->total_pairs; i++)
|
||||
{
|
||||
if(!expstruct->pairs[i].isset)
|
||||
{
|
||||
expstruct->pairs[i].layer = layer;
|
||||
expstruct->pairs[i].openpos = pos;
|
||||
expstruct->pairs[i].isset = 1;
|
||||
break;
|
||||
}
|
||||
else if(expstruct->pairs[i].layer == layer and expstruct->pairs[i].isset == 1)
|
||||
{
|
||||
expstruct->pairs[i].closepos = pos;
|
||||
expstruct->pairs[i].isset = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief This function recursively matches bracket pair in an EXPRESSION.
|
||||
\param [in,out] expstruct The expression structure. Cannot be null.
|
||||
\param expression The expression text to parse. Cannot be null.
|
||||
\param endlayer The layer to stop on. This variable is used for the recursion termination condition.
|
||||
\return The position in the \p expression mathpairs ended in.
|
||||
*/
|
||||
static int matchpairs(EXPRESSION* expstruct, const char* expression, int endlayer = 0)
|
||||
{
|
||||
int layer = endlayer;
|
||||
int len = (int)strlen(expression);
|
||||
for(int i = 0; i < len; i++)
|
||||
{
|
||||
if(expression[i] == '(')
|
||||
{
|
||||
layer++;
|
||||
int pos = (int)(expression + i - expstruct->expression);
|
||||
fillpair(expstruct, pos, layer);
|
||||
i += matchpairs(expstruct, expression + i + 1, layer);
|
||||
}
|
||||
else if(expression[i] == ')')
|
||||
{
|
||||
if(layer == endlayer)
|
||||
{
|
||||
int pos = (int)(expression + i - expstruct->expression);
|
||||
fillpair(expstruct, pos, layer);
|
||||
return i;
|
||||
}
|
||||
layer--;
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Formats a given expression. This function checks if the number of brackets is even and adds brackets to the end if needed.
|
||||
\param [in,out] exp The expression to format.
|
||||
\return The number of bracket pairs in the expression or -1 on error.
|
||||
*/
|
||||
static int expressionformat(char* exp, size_t bufsize)
|
||||
{
|
||||
int len = (int)strlen(exp);
|
||||
int open = 0;
|
||||
int close = 0;
|
||||
for(int i = 0; i < len; i++)
|
||||
{
|
||||
if(exp[i] == '(')
|
||||
open++;
|
||||
else if(exp[i] == ')')
|
||||
close++;
|
||||
}
|
||||
if(close > open)
|
||||
return -1;
|
||||
int add = open - close;
|
||||
if(add)
|
||||
{
|
||||
String closing;
|
||||
for(int i = 0; i < add; i++)
|
||||
closing += ')';
|
||||
strcat_s(exp, bufsize, closing.c_str());
|
||||
}
|
||||
return open;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Adjusts bracket pair positions to insert a new string in the expression.
|
||||
\param [in,out] exps The expression structure.
|
||||
\param cur_open The current opening bracket '(' position.
|
||||
\param cur_close The current closing bracket ')' position.
|
||||
\param cur_len The current string length in between the brackets.
|
||||
\param new_len Length of the new string.
|
||||
*/
|
||||
static void adjustpairs(EXPRESSION* exps, int cur_open, int cur_close, int cur_len, int new_len)
|
||||
{
|
||||
for(int i = 0; i < exps->total_pairs; i++)
|
||||
{
|
||||
if(exps->pairs[i].openpos > cur_open)
|
||||
exps->pairs[i].openpos += new_len - cur_len;
|
||||
if(exps->pairs[i].closepos > cur_close)
|
||||
exps->pairs[i].closepos += new_len - cur_len;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Prints value of expressions in between brackets on a certain bracket layer (expression is resolved using mathfromstring(), which means the whole thing can work recursively).
|
||||
\param [in,out] exp The expression to print. Cannot be null.
|
||||
\param bufsize Buffer size of the expression parameter.
|
||||
\param [in,out] exps The expression structure. Cannot be null.
|
||||
\param layer The layer to print.
|
||||
\param silent Value to pass on to mathfromstring().
|
||||
\param baseonly Value to pass on to mathfromstring().
|
||||
\return true if printing the layer was successful, false otherwise.
|
||||
*/
|
||||
static bool printlayer(char* exp, size_t bufsize, EXPRESSION* exps, int layer, bool silent, bool baseonly)
|
||||
{
|
||||
for(int i = 0; i < exps->total_pairs; i++)
|
||||
{
|
||||
if(exps->pairs[i].layer == layer)
|
||||
{
|
||||
const size_t explen = strlen(exp);
|
||||
Memory<char*> temp(explen + 1);
|
||||
Memory<char*> backup(explen + 1);
|
||||
|
||||
int open = exps->pairs[i].openpos;
|
||||
int close = exps->pairs[i].closepos;
|
||||
int len = close - open;
|
||||
strncpy_s(temp, temp.size(), exp + open + 1, len - 1);
|
||||
|
||||
strcpy_s(backup, backup.size(), exp + open + len + 1);
|
||||
|
||||
uint value;
|
||||
if(!mathfromstring(temp, &value, silent, baseonly, 0, 0))
|
||||
return false;
|
||||
|
||||
adjustpairs(exps, open, close, len + 1, sprintf_s(exp + open, bufsize - open, "%"fext"X", value));
|
||||
|
||||
if(*backup)
|
||||
strcat_s(exp, bufsize, backup);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Handle brackets in an expression (calculate the values of expressions in between brackets).
|
||||
\param [in,out] expression Expression to handle. Cannot be null. You need at most 16 times the input size for this.
|
||||
\param bufsize Buffer size of the expression parameter.
|
||||
\param silent Value to pass on to printlayer().
|
||||
\param baseonly Value to pass on to printlayer().
|
||||
\return true if the brackets are correctly expanded, false otherwise.
|
||||
*/
|
||||
bool mathhandlebrackets(char* expression, size_t bufsize, bool silent, bool baseonly)
|
||||
{
|
||||
EXPRESSION expstruct;
|
||||
expstruct.expression = expression;
|
||||
int total_pairs = expressionformat(expression, bufsize);
|
||||
if(total_pairs == -1)
|
||||
return false;
|
||||
else if(!total_pairs)
|
||||
return true;
|
||||
expstruct.total_pairs = total_pairs;
|
||||
|
||||
Memory<BRACKET_PAIR*> pairs(expstruct.total_pairs * sizeof(BRACKET_PAIR), "mathhandlebrackets:expstruct.pairs");
|
||||
expstruct.pairs = pairs;
|
||||
memset(expstruct.pairs, 0, expstruct.total_pairs * sizeof(BRACKET_PAIR));
|
||||
matchpairs(&expstruct, expression);
|
||||
int deepest = 0;
|
||||
for(int i = 0; i < expstruct.total_pairs; i++)
|
||||
if(expstruct.pairs[i].layer > deepest)
|
||||
deepest = expstruct.pairs[i].layer;
|
||||
|
||||
for(int i = deepest; i > 0; i--)
|
||||
if(!printlayer(expression, bufsize, &expstruct, i, silent, baseonly))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Calculate the value of an expression string.
|
||||
\param string The string to calculate the value of. Cannot be null.
|
||||
\param [in,out] value The resulting value. Cannot be null.
|
||||
\param silent Value to pass on to valfromstring().
|
||||
\param baseonly Value to pass on to valfromstring().
|
||||
\param [in,out] value_size Value to pass on to valfromstring(). Can be null.
|
||||
\param [in,out] isvar Value to pass on to valfromstring(). Can be null.
|
||||
\return true if the string was successfully parsed and the value was calculated.
|
||||
*/
|
||||
bool mathfromstring(const char* string, uint* value, bool silent, bool baseonly, int* value_size, bool* isvar)
|
||||
{
|
||||
int highestop = 0;
|
||||
int highestop_pos = 0;
|
||||
int len = (int)strlen(string);
|
||||
bool negative = false;
|
||||
if(*string == '-')
|
||||
{
|
||||
negative = true;
|
||||
string++;
|
||||
}
|
||||
for(int i = 0; i < len; i++)
|
||||
{
|
||||
int curop = mathisoperator(string[i]);
|
||||
if(curop > 1 and curop > highestop)
|
||||
{
|
||||
highestop = curop;
|
||||
highestop_pos = i;
|
||||
}
|
||||
}
|
||||
if(!highestop)
|
||||
return valfromstring(string, value, silent, baseonly, value_size, isvar, 0);
|
||||
Memory<char*> strleft(len + 1 + negative, "mathfromstring:strleft");
|
||||
Memory<char*> strright(len + 1, "mathfromstring:strright");
|
||||
strncpy(strleft, string - negative, highestop_pos + negative);
|
||||
strcpy(strright, string + highestop_pos + 1);
|
||||
strcpy(strleft, StringUtils::Trim(strleft).c_str());
|
||||
strcpy(strright, StringUtils::Trim(strright).c_str());
|
||||
//dprintf("left: %s, right: %s, op: %c\n", strleft(), strright(), string[highestop_pos]);
|
||||
if(!*strright)
|
||||
return false;
|
||||
uint right = 0;
|
||||
if(!valfromstring(strright, &right, silent, baseonly))
|
||||
return false;
|
||||
if(string[highestop_pos] == '~')
|
||||
{
|
||||
right = ~right;
|
||||
if(!strlen(strleft))
|
||||
{
|
||||
*value = right;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
uint left = 0;
|
||||
if(!valfromstring(strleft, &left, silent, baseonly))
|
||||
return false;
|
||||
bool math_ok;
|
||||
if(valuesignedcalc())
|
||||
math_ok = mathdosignedoperation(string[highestop_pos], left, right, (sint*)value);
|
||||
else
|
||||
math_ok = mathdounsignedoperation(string[highestop_pos], left, right, value);
|
||||
return math_ok;
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
#ifndef _MATH_H
|
||||
#define _MATH_H
|
||||
|
||||
#include "_global.h"
|
||||
|
||||
int mathisoperator(char ch);
|
||||
void mathformat(char* text);
|
||||
bool mathcontains(const char* text);
|
||||
bool mathhandlebrackets(char* expression, size_t bufsize, bool silent, bool baseonly);
|
||||
bool mathfromstring(const char* string, uint* value, bool silent, bool baseonly, int* value_size, bool* isvar);
|
||||
bool mathdounsignedoperation(char op, uint left, uint right, uint* result);
|
||||
bool mathdosignedoperation(char op, sint left, sint right, sint* result);
|
||||
|
||||
#endif // _MATH_H
|
||||
|
|
@ -14,6 +14,7 @@
|
|||
#include "symbolinfo.h"
|
||||
#include "module.h"
|
||||
#include "label.h"
|
||||
#include "expressionparser.h"
|
||||
|
||||
static bool dosignedcalc = false;
|
||||
|
||||
|
|
@ -1497,9 +1498,9 @@ static bool ishexnumber(const char* string)
|
|||
\param [out] value_size This function can output the value size parsed (for example memory location size or register size). Can be null.
|
||||
\param [out] isvar This function can output if the expression is variable (for example memory locations, registers or variables are variable). Can be null.
|
||||
\param [out] hexonly This function can output if the output value should only be printed as hexadecimal (for example addresses). Can be null.
|
||||
\return true if the expression was parsed successfull, false otherwise.
|
||||
\return true if the expression was parsed successful, false otherwise.
|
||||
*/
|
||||
bool valfromstring(const char* string, uint* value, bool silent, bool baseonly, int* value_size, bool* isvar, bool* hexonly)
|
||||
bool valfromstring_noexpr(const char* string, uint* value, bool silent, bool baseonly, int* value_size, bool* isvar, bool* hexonly)
|
||||
{
|
||||
if(!value or !string)
|
||||
return false;
|
||||
|
|
@ -1508,50 +1509,7 @@ bool valfromstring(const char* string, uint* value, bool silent, bool baseonly,
|
|||
*value = 0;
|
||||
return true;
|
||||
}
|
||||
else if(mathcontains(string)) //handle math
|
||||
{
|
||||
int len = (int)strlen(string);
|
||||
Memory<char*> newstring(len * 2 + 1, "valfromstring:newstring");
|
||||
if(strstr(string, "[")) //memory brackets: []
|
||||
{
|
||||
for(int i = 0, j = 0; i < len; i++)
|
||||
{
|
||||
if(string[i] == ']')
|
||||
j += sprintf(newstring + j, ")");
|
||||
else if(isdigit(string[i]) and string[i + 1] == ':' and string[i + 2] == '[') //n:[
|
||||
{
|
||||
j += sprintf(newstring + j, "@%c:(", string[i]);
|
||||
i += 2;
|
||||
}
|
||||
else if(string[i] == '[')
|
||||
j += sprintf(newstring + j, "@(");
|
||||
else
|
||||
j += sprintf(newstring + j, "%c", string[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
strcpy_s(newstring, newstring.size(), string);
|
||||
Memory<char*> string_(len * 16 + deflen, "valfromstring:string_");
|
||||
strcpy_s(string_, string_.size(), newstring);
|
||||
int add = 0;
|
||||
bool negative = (*string_ == '-');
|
||||
while(mathisoperator(string_[add + negative]) > 2)
|
||||
add++;
|
||||
if(!mathhandlebrackets(string_ + add, string_.size() - add, silent, baseonly))
|
||||
return false;
|
||||
return mathfromstring(string_ + add, value, silent, baseonly, value_size, isvar);
|
||||
}
|
||||
else if(*string == '-') //negative value
|
||||
{
|
||||
uint val;
|
||||
if(!valfromstring(string + 1, &val, silent, baseonly, value_size, isvar, hexonly))
|
||||
return false;
|
||||
val *= ~0;
|
||||
if(value)
|
||||
*value = val;
|
||||
return true;
|
||||
}
|
||||
else if(*string == '@' or strstr(string, "[")) //memory location
|
||||
else if(string[0] == '[' || (isdigit(string[0]) && string[1] == ':' && string[2] == '[')) //memory location
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
{
|
||||
|
|
@ -1565,37 +1523,33 @@ bool valfromstring(const char* string, uint* value, bool silent, bool baseonly,
|
|||
return true;
|
||||
}
|
||||
int len = (int)strlen(string);
|
||||
Memory<char*> newstring(len * 2 + 1, "valfromstring:newstring");
|
||||
if(strstr(string, "["))
|
||||
|
||||
String newstring;
|
||||
bool foundStart = false;
|
||||
for(int i = 0; i < len; i++)
|
||||
{
|
||||
for(int i = 0, j = 0; i < len; i++)
|
||||
{
|
||||
if(string[i] == ']')
|
||||
j += sprintf(newstring + j, ")");
|
||||
else if(isdigit(string[i]) and string[i + 1] == ':' and string[i + 2] == '[') //n:[
|
||||
{
|
||||
j += sprintf(newstring + j, "@%c:(", string[i]);
|
||||
i += 2;
|
||||
}
|
||||
else if(string[i] == '[')
|
||||
j += sprintf(newstring + j, "@(");
|
||||
else
|
||||
j += sprintf(newstring + j, "%c", string[i]);
|
||||
}
|
||||
if(string[i] == '[')
|
||||
foundStart = true;
|
||||
else if(string[i] == ']')
|
||||
break;
|
||||
else if(foundStart)
|
||||
newstring += string[i];
|
||||
}
|
||||
else
|
||||
strcpy_s(newstring, newstring.size(), string);
|
||||
|
||||
int read_size = sizeof(uint);
|
||||
int add = 1;
|
||||
if(newstring[2] == ':' and isdigit((newstring[1]))) //@n: (number of bytes to read)
|
||||
if(string[1] == ':') //n:[ (number of bytes to read)
|
||||
{
|
||||
add += 2;
|
||||
int new_size = newstring[1] - 0x30;
|
||||
int new_size = string[0] - '0';
|
||||
if(new_size < read_size)
|
||||
read_size = new_size;
|
||||
}
|
||||
if(!valfromstring(newstring + add, value, silent, baseonly))
|
||||
if(!valfromstring(newstring.c_str(), value, silent, baseonly))
|
||||
{
|
||||
dprintf("noexpr failed on %s\n", newstring.c_str());
|
||||
return false;
|
||||
}
|
||||
uint addr = *value;
|
||||
*value = 0;
|
||||
if(!MemRead((void*)addr, value, read_size, 0))
|
||||
|
|
@ -1610,7 +1564,7 @@ bool valfromstring(const char* string, uint* value, bool silent, bool baseonly,
|
|||
*isvar = true;
|
||||
return true;
|
||||
}
|
||||
else if(isregister(string)) //register
|
||||
else if(isregister(string)) //register
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
{
|
||||
|
|
@ -1628,7 +1582,7 @@ bool valfromstring(const char* string, uint* value, bool silent, bool baseonly,
|
|||
*isvar = true;
|
||||
return true;
|
||||
}
|
||||
else if(*string == '!' and isflag(string + 1)) //flag
|
||||
else if(*string == '!' and isflag(string + 1)) //flag
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
{
|
||||
|
|
@ -1652,7 +1606,7 @@ bool valfromstring(const char* string, uint* value, bool silent, bool baseonly,
|
|||
*isvar = true;
|
||||
return true;
|
||||
}
|
||||
else if(isdecnumber(string)) //decimal numbers come 'first'
|
||||
else if(isdecnumber(string)) //decimal numbers come 'first'
|
||||
{
|
||||
if(value_size)
|
||||
*value_size = 0;
|
||||
|
|
@ -1661,7 +1615,7 @@ bool valfromstring(const char* string, uint* value, bool silent, bool baseonly,
|
|||
sscanf(string + 1, "%"fext"u", value);
|
||||
return true;
|
||||
}
|
||||
else if(ishexnumber(string)) //then hex numbers
|
||||
else if(ishexnumber(string)) //then hex numbers
|
||||
{
|
||||
if(value_size)
|
||||
*value_size = 0;
|
||||
|
|
@ -1676,13 +1630,13 @@ bool valfromstring(const char* string, uint* value, bool silent, bool baseonly,
|
|||
}
|
||||
if(baseonly)
|
||||
return false;
|
||||
else if(valapifromstring(string, value, value_size, true, silent, hexonly)) //then come APIs
|
||||
else if(valapifromstring(string, value, value_size, true, silent, hexonly)) //then come APIs
|
||||
return true;
|
||||
else if(LabelFromString(string, value)) //then come labels
|
||||
else if(LabelFromString(string, value)) //then come labels
|
||||
return true;
|
||||
else if(SymAddrFromName(string, value)) //then come symbols
|
||||
else if(SymAddrFromName(string, value)) //then come symbols
|
||||
return true;
|
||||
else if(varget(string, value, value_size, 0)) //finally variables
|
||||
else if(varget(string, value, value_size, 0)) //finally variables
|
||||
{
|
||||
if(isvar)
|
||||
*isvar = true;
|
||||
|
|
@ -1693,6 +1647,34 @@ bool valfromstring(const char* string, uint* value, bool silent, bool baseonly,
|
|||
return false; //nothing was OK
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Gets a value from a string. This function can parse expressions, memory locations, registers, flags, API names, labels, symbols and variables.
|
||||
\param string The string to parse.
|
||||
\param [out] value The value of the expression. This value cannot be null.
|
||||
\param silent true to not output anything to the console.
|
||||
\param baseonly true to skip parsing API names, labels, symbols and variables (basic expressions only).
|
||||
\param [out] value_size This function can output the value size parsed (for example memory location size or register size). Can be null.
|
||||
\param [out] isvar This function can output if the expression is variable (for example memory locations, registers or variables are variable). Can be null.
|
||||
\param [out] hexonly This function can output if the output value should only be printed as hexadecimal (for example addresses). Can be null.
|
||||
\return true if the expression was parsed successful, false otherwise.
|
||||
*/
|
||||
bool valfromstring(const char* string, uint* value, bool silent, bool baseonly, int* value_size, bool* isvar, bool* hexonly)
|
||||
{
|
||||
if(!value or !string)
|
||||
return false;
|
||||
if(!*string)
|
||||
{
|
||||
*value = 0;
|
||||
return true;
|
||||
}
|
||||
ExpressionParser parser(string);
|
||||
uint result;
|
||||
if(!parser.calculate(result, valuesignedcalc(), silent, baseonly, value_size, isvar, hexonly))
|
||||
return false;
|
||||
*value = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Checks if a string is long enough.
|
||||
\param str The string to check.
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
bool valuesignedcalc();
|
||||
void valuesetsignedcalc(bool a);
|
||||
bool valapifromstring(const char* name, uint* value, int* value_size, bool printall, bool silent, bool* hexonly);
|
||||
bool valfromstring_noexpr(const char* string, uint* value, bool silent = true, bool baseonly = false, int* value_size = 0, bool* isvar = 0, bool* hexonly = 0);
|
||||
bool valfromstring(const char* string, uint* value, bool silent = true, bool baseonly = false, int* value_size = 0, bool* isvar = 0, bool* hexonly = 0);
|
||||
bool valflagfromstring(uint eflags, const char* string);
|
||||
bool valtostring(const char* string, uint value, bool silent);
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
<ClCompile Include="disasm_helper.cpp" />
|
||||
<ClCompile Include="error.cpp" />
|
||||
<ClCompile Include="exception.cpp" />
|
||||
<ClCompile Include="expressionparser.cpp" />
|
||||
<ClCompile Include="filereader.cpp" />
|
||||
<ClCompile Include="function.cpp" />
|
||||
<ClCompile Include="functionanalysis.cpp" />
|
||||
|
|
@ -42,7 +43,6 @@
|
|||
<ClCompile Include="label.cpp" />
|
||||
<ClCompile Include="loop.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="math.cpp" />
|
||||
<ClCompile Include="memory.cpp" />
|
||||
<ClCompile Include="module.cpp" />
|
||||
<ClCompile Include="msgqueue.cpp" />
|
||||
|
|
@ -96,6 +96,7 @@
|
|||
<ClInclude Include="dynamicmem.h" />
|
||||
<ClInclude Include="error.h" />
|
||||
<ClInclude Include="exception.h" />
|
||||
<ClInclude Include="expressionparser.h" />
|
||||
<ClInclude Include="filereader.h" />
|
||||
<ClInclude Include="function.h" />
|
||||
<ClInclude Include="functionanalysis.h" />
|
||||
|
|
@ -109,7 +110,6 @@
|
|||
<ClInclude Include="lz4\lz4.h" />
|
||||
<ClInclude Include="lz4\lz4file.h" />
|
||||
<ClInclude Include="lz4\lz4hc.h" />
|
||||
<ClInclude Include="math.h" />
|
||||
<ClInclude Include="memory.h" />
|
||||
<ClInclude Include="module.h" />
|
||||
<ClInclude Include="msgqueue.h" />
|
||||
|
|
|
|||
|
|
@ -105,9 +105,6 @@
|
|||
<ClCompile Include="console.cpp">
|
||||
<Filter>Source Files\Core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="math.cpp">
|
||||
<Filter>Source Files\Core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="threading.cpp">
|
||||
<Filter>Source Files\Core</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -219,6 +216,9 @@
|
|||
<ClCompile Include="filereader.cpp">
|
||||
<Filter>Source Files\Utilities</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="expressionparser.cpp">
|
||||
<Filter>Source Files\Core</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="x64_dbg.h">
|
||||
|
|
@ -260,9 +260,6 @@
|
|||
<ClInclude Include="command.h">
|
||||
<Filter>Header Files\Core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="math.h">
|
||||
<Filter>Header Files\Core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="threading.h">
|
||||
<Filter>Header Files\Core</Filter>
|
||||
</ClInclude>
|
||||
|
|
@ -518,5 +515,8 @@
|
|||
<ClInclude Include="filereader.h">
|
||||
<Filter>Header Files\Utilities</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="expressionparser.h">
|
||||
<Filter>Header Files\Core</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Loading…
Reference in New Issue