вам нужно разделить вычисления на несколько шагов
- скопировать выражение в доступную для записи память и проверить / нормализовать его:
. Проверить, что все символы действительны (положительные)
. Удалить пробелы
. Преобразовать все в нижний (или верхний) регистр (если вы используете шестнадцатеричные выражения)
. Некоторые операторы принимают 2 символа ( == , ! = , > = , <= </em>, << </em>, >> , || , && ) - заменить его на одиночный символ из недопустимого (отрицательного) диапазона
удалить
() , если существует - вычислить выражения в
() :
. Найти сначала ) символ с начала
. Найти последний ( перед ним.
. Проверить, что после ) и до ( были символы-разделители (оператор или начало / конец строки), но не di git.
.формат новой строки, где вы заменяете (..) на цифровой результат
удалить (вычислить) все унарные операторы (
+, -,!, ~ )
. Унарные операторы - справа должны иметь di git, а слева - другой оператор (или начало строки), но не di git
.формат новой строки с результатом унарного оператора
удалить (вычислить) все двоичные операторы.
. Нам нужно вычислить в обратном порядке приоритета - поэтому сначала нужно вычислить / удалить операторы с самым низким приоритетом.
.so нужно сделать l oop операторами (от низкого до высокого приоритета) - символ оператора поиска в строке.
.Если найдено - A op B - вычислить отдельно A и B , а затем применить op .
преобразовать строку в целое число
. Теперь, после того как все () и операторы удалены - только строка * git должна быть в строке
пример кода:
namespace Eval
{
typedef INT_PTR (* fn_b_op)(INT_PTR a, INT_PTR b);
typedef INT_PTR (* fn_u_op)(INT_PTR a);
struct b_op_arr { fn_b_op pfn; char c; };
struct u_op_arr { fn_u_op pfn; char c; };
struct name_to_char { char b[3]; char c;};
static INT_PTR fn1_bnt(INT_PTR a){ return !a; }
static INT_PTR fn1_not(INT_PTR a){ return ~a; }
static INT_PTR fn1_add(INT_PTR a){ return +a; }
static INT_PTR fn1_sub(INT_PTR a){ return -a; }
static INT_PTR fn2Land(INT_PTR a,INT_PTR b){ return a && b; }
static INT_PTR fn2_Lor(INT_PTR a,INT_PTR b){ return a || b; }
static INT_PTR fn2_equ(INT_PTR a,INT_PTR b){ return a == b; }
static INT_PTR fn2_nqu(INT_PTR a,INT_PTR b){ return a != b; }
static INT_PTR fn2_lqu(INT_PTR a,INT_PTR b){ return a < b; }
static INT_PTR fn2_gqu(INT_PTR a,INT_PTR b){ return a > b; }
static INT_PTR fn2_leu(INT_PTR a,INT_PTR b){ return a <= b; }
static INT_PTR fn2_geu(INT_PTR a,INT_PTR b){ return a >= b; }
static INT_PTR fn2_add(INT_PTR a,INT_PTR b){ return a + b; }
static INT_PTR fn2_sub(INT_PTR a,INT_PTR b){ return a - b; }
static INT_PTR fn2_mul(INT_PTR a,INT_PTR b){ return a * b; }
static INT_PTR fn2_div(INT_PTR a,INT_PTR b){ return a / b; }
static INT_PTR fn2_dv2(INT_PTR a,INT_PTR b){ return a % b; }
static INT_PTR fn2_lsh(INT_PTR a,INT_PTR b){ return (UINT_PTR)a << b; }
static INT_PTR fn2_rsh(INT_PTR a,INT_PTR b){ return (UINT_PTR)a >> b; }
static INT_PTR fn2_xor(INT_PTR a,INT_PTR b){ return a ^ b; }
static INT_PTR fn2_and(INT_PTR a,INT_PTR b){ return a & b; }
static INT_PTR fn2__or(INT_PTR a,INT_PTR b){ return a | b; }
enum /*: char*/ { equ = -0x80, not_equ, less_equ, gre_equ, l_or, l_and, r_shift, l_shift };
inline static b_op_arr b_arr[] =
{
{fn2_mul, '*'}, {fn2_div, '/'}, {fn2_lsh, l_shift}, {fn2_rsh, r_shift},
{fn2_xor, '^'}, {fn2_dv2, '%'}, {fn2_and, '&'}, {fn2__or, '|'},
{fn2_equ, equ}, {fn2_nqu, not_equ}, {fn2_lqu, '<'}, {fn2_gqu, '>'},
{fn2_leu, less_equ},{fn2_geu, gre_equ},{fn2_add, '+'}, {fn2_sub, '-'},
{fn2Land, l_and}, {fn2_Lor, l_or}
};
inline static u_op_arr u_arr[] =
{
{fn1_add, '+'}, {fn1_sub, '-'}, {fn1_bnt,'!'}, {fn1_not,'~'}
};
inline static name_to_char _2_to_1[] =
{
{"==", equ}, {"!=", not_equ}, {"<=", less_equ}, {">=", gre_equ },
{">>", r_shift}, {"<<", l_shift}, {"||", l_or}, {"&&", l_and},
};
void initBits(LONG bits[], const char cc[], ULONG n)
{
do
{
_bittestandset(bits, cc[--n]);
} while (n);
}
static bool IsSeparatorSymbol(char c)
{
static LONG bits[8];
static bool bInit;
if (!bInit)
{
// acquire
static const char cc[] = {
'*', '/', '+', '-', '^', '%', '&', '|', '<', '>', '!', '~', '(', ')',
equ, not_equ, less_equ, gre_equ, l_or, l_and, r_shift, l_shift, 0
};
initBits(bits, cc, _countof(cc));
// release
bInit = true;
}
return _bittest(bits, c);
}
static bool IsUnaryOpSymbol(char c)
{
static LONG bits[8];
static bool bInit;
if (!bInit)
{
// acquire
static char cc[] = {
'+', '-', '!', '~'
};
initBits(bits, cc, _countof(cc));
// release
bInit = true;
}
return _bittest(bits, c);
}
static bool IsDigit(char c)
{
static LONG bits[8];
static bool bInit;
if (!bInit)
{
// acquire
static char cc[] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
initBits(bits, cc, _countof(cc));
// release
bInit = true;
}
return _bittest(bits, c);
}
__int64 strtol64_16(char* sz, char** psz)
{
__int64 r = 0;
while (char c = *sz)
{
ULONG d;
if ((ULONG)(c - '0') <= '9' - '0')
{
d = (c - '0');
}
else if ((ULONG)(c - 'a') <= 'z' - 'a')
{
d = (c - 'a') + 10;
}
else
{
break;
}
r = (r << 4) + d;
sz++;
}
*psz = sz;
return r;
}
bool Normalize(const char* psz, char* buf, size_t s)
{
int len = 0;
do
{
--s;
char c = *psz++, d;
// is valid char
if (c < 0) return false;
// skip space
if (c == ' ') continue;
if ((ULONG)(c - 'A') < (ULONG)('Z' - 'A'))
{
c += 'a' - 'A';
}
// not last char
if (s)
{
d = *psz;
int k = _countof(_2_to_1);
do
{
if (_2_to_1[--k].b[0] == c && _2_to_1[k].b[1] == d)
{
c = _2_to_1[k].c, psz++, --s;
break;
}
} while (k);
}
*buf++ = c, len++;
} while (s);
return 0 < len;
}
char* format_new_str(const char* a, INT_PTR r, const char* b)
{
static const char format[] = "%s%I64x%s";
int len = _scprintf(format, a, r, b);
if (0 < len)
{
if (char* buf = new char [++len])
{
if (0 < sprintf_s(buf, len, format, a, r, b))
{
DbgPrint("++%p\n\"%s\"\n", buf, buf);
return buf;
}
delete buf;
}
}
return 0;
}
bool _calc (char* str, INT_PTR& result)
{
DbgPrint("\"%s\"\n", str);
struct SB
{
char* str;
SB() : str(0) {}
~SB()
{
operator <<(0);
}
void operator <<(char* psz)
{
if (str)
{
DbgPrint("--%p\n", str);
delete [] str;
}
str = psz;
}
} sb;
size_t len = strlen(str);
if (!len)
{
return false;
}
char b, c;
int l;
INT_PTR r, q;
//1. remove ( )
char *psz = str, *pc = 0, *buf;
for (;;)
{
switch (*psz++)
{
case '(':
pc = psz;
continue;
case ')':
if (!pc || !IsSeparatorSymbol(*psz) || (pc > str + 1 && !IsSeparatorSymbol(pc[-2]))) return false;
psz[-1] = 0, pc[-1] = 0;
if (_calc(pc, r) && (buf = format_new_str(str, r, psz)))
{
sb << buf;
psz = str = buf, pc = 0;
continue;
}
return false;
case 0:
goto __2;
}
}
__2:
//2. remove unary op
psz = str;
do
{
if (IsDigit(c = *psz) && str < psz && IsUnaryOpSymbol(c = psz[-1]) && (psz == str + 1 || IsSeparatorSymbol(psz[-2])))
{
psz[-1] = 0;
l = _countof(u_arr);
do
{
if (u_arr[--l].c == c)
{
r = strtol64_16(psz, &psz);
if (IsSeparatorSymbol(*psz))
{
r = u_arr[l].pfn(r);
if (buf = format_new_str(str, r, psz))
{
sb << buf;
psz = str = buf;
goto __2;
}
}
break;
}
} while (l);
return false;
}
} while (psz++, c);
//3. remove binary op
l = _countof(b_arr);
do
{
c = b_arr[--l].c;
psz = str;
do
{
if (c == (b = *psz++))
{
psz[-1] = 0;
if (_calc(psz, q) && _calc(str, r))
{
result = b_arr[l].pfn(r, q);
return true;
}
return false;
}
} while (b);
} while (l);
result = strtol64_16(str, &str);
return !*str;
}
bool calc(const char* psz, INT_PTR& result)
{
bool fOk = false;
if (size_t s = strlen(psz))
{
if (char* buf = new char[++s])
{
if (Normalize(psz, buf, s))
{
fOk = _calc(buf, result);
}
delete [] buf;
}
}
return fOk;
}
};
использование
INT_PTR r;
Eval::calc(str, r);