2012-01-31 01:45:17 +00:00
|
|
|
/* ported to C by pancake for r2 in 2012 */
|
|
|
|
// TODO: support buffer instead of io
|
|
|
|
/*
|
|
|
|
Reference Chapter 6:
|
|
|
|
"The C++ Programming Language", Special Edition.
|
|
|
|
Bjarne Stroustrup,Addison-Wesley Pub Co; 3 edition (February 15, 2000)
|
|
|
|
ISBN: 0201700735
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2012-02-14 03:41:40 +00:00
|
|
|
#include <r_util.h>
|
2012-01-31 01:45:17 +00:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
/* TODO: move into libr/include */
|
|
|
|
#define ut64 unsigned long long
|
|
|
|
typedef struct {
|
|
|
|
double d;
|
|
|
|
ut64 n;
|
|
|
|
} NumValue;
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
NAME, NUMBER, END, INC, DEC,
|
|
|
|
PLUS='+', MINUS='-', MUL='*', DIV='/',
|
2012-02-12 22:45:04 +00:00
|
|
|
//XOR='^', OR='|', AND='&',
|
2012-01-31 01:45:17 +00:00
|
|
|
PRINT=';', ASSIGN='=', LP='(', RP=')'
|
|
|
|
} Token;
|
|
|
|
|
|
|
|
/* accessors */
|
|
|
|
static inline NumValue Nset(ut64 v) { NumValue n; n.d = (double)v; n.n = v; return n; }
|
|
|
|
static inline NumValue Nsetf(double v) { NumValue n; n.d = v; n.n = (ut64)v; return n; }
|
|
|
|
static inline NumValue Naddf(NumValue n, double v) { n.d += v; n.n += (ut64)v; return n; }
|
|
|
|
static inline NumValue Naddi(NumValue n, ut64 v) { n.d += (double)v; n.n += v; return n; }
|
|
|
|
static inline NumValue Nsubi(NumValue n, ut64 v) { n.d -= (double)v; n.n -= v; return n; }
|
|
|
|
static inline NumValue Nadd(NumValue n, NumValue v) { n.d += v.d; n.n += v.n; return n; }
|
|
|
|
static inline NumValue Nsub(NumValue n, NumValue v) { n.d -= v.d; n.n -= v.n; return n; }
|
|
|
|
static inline NumValue Nmul(NumValue n, NumValue v) { n.d *= v.d; n.n *= v.n; return n; }
|
|
|
|
static inline NumValue Ndiv(NumValue n, NumValue v) { n.d /= v.d; n.n /= v.n; return n; }
|
|
|
|
|
|
|
|
static NumValue expr(int);
|
|
|
|
static NumValue term(int);
|
|
|
|
static void error(const char *);
|
|
|
|
static NumValue prim(int);
|
|
|
|
static Token get_token();
|
|
|
|
|
2012-02-14 03:41:40 +00:00
|
|
|
static RNum *calc_num = NULL;
|
|
|
|
|
2012-01-31 01:45:17 +00:00
|
|
|
/* global shit */
|
|
|
|
#define STRSZ 128
|
|
|
|
static Token curr_tok = PRINT;
|
|
|
|
static NumValue number_value = { 0 };
|
|
|
|
static char string_value[STRSZ];
|
|
|
|
static int errors = 0;
|
|
|
|
static char oc = 0;
|
|
|
|
|
|
|
|
static void error(const char *s) {
|
|
|
|
errors++;
|
2012-02-14 03:41:40 +00:00
|
|
|
//fprintf (stderr, "error: %s\n", s);
|
2012-01-31 01:45:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static NumValue expr(int get) {
|
|
|
|
NumValue left = term (get);
|
|
|
|
for (;;) {
|
|
|
|
if (curr_tok == PLUS)
|
|
|
|
left = Nadd (left, term (1));
|
|
|
|
else
|
|
|
|
if (curr_tok == MINUS)
|
|
|
|
left = Nsub (left, term (1));
|
|
|
|
else return left;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static NumValue term(int get) {
|
|
|
|
NumValue left = prim (get);
|
|
|
|
for (;;) {
|
|
|
|
if (curr_tok == MUL) {
|
|
|
|
left = Nmul (left, prim (1));
|
|
|
|
} else
|
|
|
|
if (curr_tok == DIV) {
|
|
|
|
NumValue d = prim (1);
|
|
|
|
if (!d.d) {
|
|
|
|
error ("divide by 0");
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
left = Ndiv (left, d);
|
|
|
|
} else return left;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static NumValue prim(int get) {
|
|
|
|
NumValue v = {0};
|
|
|
|
if (get) get_token ();
|
|
|
|
switch (curr_tok) {
|
|
|
|
case NUMBER:
|
|
|
|
v = number_value;
|
|
|
|
get_token ();
|
|
|
|
return v;
|
|
|
|
case NAME:
|
2012-02-14 03:41:40 +00:00
|
|
|
//fprintf (stderr, "error: unknown keyword (%s)\n", string_value);
|
2012-01-31 01:45:17 +00:00
|
|
|
//double& v = table[string_value];
|
2012-02-14 03:41:40 +00:00
|
|
|
v = Nset (r_num_get (calc_num, string_value));
|
2012-01-31 01:45:17 +00:00
|
|
|
get_token ();
|
|
|
|
if (curr_tok == ASSIGN)
|
|
|
|
v = expr (1);
|
|
|
|
if (curr_tok == INC) Naddi (v, 1);
|
|
|
|
if (curr_tok == DEC) Nsubi (v, 1);
|
|
|
|
return v;
|
|
|
|
case INC: return Naddi (prim (1), 1);
|
|
|
|
case DEC: return Naddi (prim (1), -1);
|
|
|
|
case MINUS: return Nsub (v, prim (1));
|
|
|
|
case LP:
|
|
|
|
v = expr (1);
|
|
|
|
if (curr_tok == RP)
|
|
|
|
get_token ();
|
|
|
|
else error (" ')' expected");
|
|
|
|
default:
|
|
|
|
error ("primary expected");
|
|
|
|
}
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cin_putback (char c) {
|
|
|
|
oc = c;
|
|
|
|
}
|
|
|
|
|
2012-02-14 03:41:40 +00:00
|
|
|
static int calc_i = 0;
|
|
|
|
static const char *calc_buf = NULL;
|
|
|
|
|
2012-01-31 01:45:17 +00:00
|
|
|
static int cin_get(char *c) {
|
|
|
|
if (oc) {
|
|
|
|
*c = oc;
|
|
|
|
oc = 0;
|
|
|
|
} else {
|
2012-02-14 03:41:40 +00:00
|
|
|
if (!calc_buf)
|
2012-01-31 01:45:17 +00:00
|
|
|
return 0;
|
2012-02-14 03:41:40 +00:00
|
|
|
*c = calc_buf[calc_i];
|
|
|
|
if (*c) calc_i++;
|
|
|
|
else return 0;
|
2012-01-31 01:45:17 +00:00
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cin_get_num(NumValue *n) {
|
|
|
|
double d;
|
|
|
|
char str[128];
|
|
|
|
int i = 0;
|
|
|
|
char c;
|
|
|
|
str[0] = 0;
|
|
|
|
while (cin_get (&c)) {
|
|
|
|
if (c!='.' && !isalnum (c)) {
|
|
|
|
cin_putback (c);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i<STRSZ)
|
|
|
|
str[i++] = c;
|
|
|
|
}
|
|
|
|
str[i] = 0;
|
2012-02-14 03:41:40 +00:00
|
|
|
*n = Nset (r_num_get (calc_num, str));
|
|
|
|
#if 0
|
|
|
|
// XXX: use r_num_get here
|
2012-01-31 01:45:17 +00:00
|
|
|
if (str[0]=='0' && str[1]=='x') {
|
|
|
|
ut64 x = 0;
|
|
|
|
if (sscanf (str+2, "%llx", &x)<1)
|
|
|
|
return 0;
|
|
|
|
*n = Nset (x);
|
2012-02-14 03:41:40 +00:00
|
|
|
} else
|
|
|
|
if (strchr (str, '.')) {
|
|
|
|
if (sscanf (str, "%lf", &d)<1)
|
|
|
|
return 0;
|
|
|
|
*n = Nsetf (d);
|
|
|
|
} else {
|
|
|
|
ut64 u;
|
|
|
|
if (sscanf (str, "%"PFMT64d, &u)<1)
|
|
|
|
return 0;
|
|
|
|
*n = Nset (u);
|
2012-01-31 01:45:17 +00:00
|
|
|
}
|
2012-02-14 03:41:40 +00:00
|
|
|
#endif
|
2012-01-31 01:45:17 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Token get_token() {
|
|
|
|
char c, ch;
|
|
|
|
|
|
|
|
do { if (!cin_get (&ch)) return curr_tok = END;
|
|
|
|
} while (ch!='\n' && isspace (ch));
|
|
|
|
|
|
|
|
switch (ch) {
|
|
|
|
case 0: return curr_tok = END;
|
|
|
|
case ';':
|
|
|
|
case '\n':
|
|
|
|
return curr_tok = PRINT;
|
|
|
|
case '+': // added for ++name and name++
|
|
|
|
if (cin_get (&c) && c == '+')
|
|
|
|
return curr_tok = INC;
|
|
|
|
cin_putback (c);
|
|
|
|
return curr_tok = (Token) ch;
|
|
|
|
case '-':
|
|
|
|
if (cin_get (&c) && c == '-')
|
|
|
|
return curr_tok = DEC;
|
|
|
|
cin_putback (c);
|
|
|
|
return curr_tok = (Token) ch;
|
|
|
|
case '*':
|
|
|
|
case '/':
|
|
|
|
case '(':
|
|
|
|
case ')':
|
|
|
|
case '=':
|
|
|
|
return curr_tok = (Token) ch;
|
|
|
|
case '0':case '1': case '2': case '3': case '4':
|
|
|
|
case '5': case '6': case '7': case '8': case '9':
|
|
|
|
case '.':
|
|
|
|
cin_putback (ch);
|
|
|
|
if (!cin_get_num (&number_value)) {
|
|
|
|
error ("invalid number conversion\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return curr_tok = NUMBER;
|
|
|
|
default:
|
2012-02-14 03:41:40 +00:00
|
|
|
//if (ch=='$' || isalpha (ch)) {
|
|
|
|
{
|
2012-01-31 01:45:17 +00:00
|
|
|
int i = 0;
|
|
|
|
string_value[i++] = ch;
|
2012-02-14 03:41:40 +00:00
|
|
|
while (cin_get (&ch)) { // && ( isalnum (ch) || ch=='$')) {
|
2012-01-31 01:45:17 +00:00
|
|
|
if (i>=STRSZ) {
|
|
|
|
error ("string too long");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
string_value[i++] = ch;
|
|
|
|
}
|
|
|
|
string_value[i] = 0;
|
|
|
|
cin_putback (ch);
|
|
|
|
return curr_tok = NAME;
|
2012-02-14 03:41:40 +00:00
|
|
|
}
|
|
|
|
//}
|
2012-01-31 01:45:17 +00:00
|
|
|
error ("bad token");
|
|
|
|
return curr_tok = PRINT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-14 03:41:40 +00:00
|
|
|
void load_token(const char *s) {
|
|
|
|
calc_i = 0;
|
|
|
|
calc_buf = s;
|
|
|
|
}
|
|
|
|
|
2012-01-31 01:45:17 +00:00
|
|
|
#ifdef TEST
|
|
|
|
int main(int argc, char* argv[]) {
|
|
|
|
NumValue n;
|
|
|
|
while (!feof (stdin)) {
|
|
|
|
get_token ();
|
|
|
|
if (curr_tok == END) break;
|
|
|
|
if (curr_tok == PRINT) continue;
|
|
|
|
n = expr (0);
|
|
|
|
if (n.d == ((double)(int)n.d))
|
|
|
|
printf ("%llx\n", n.n);
|
|
|
|
else printf ("%lf\n", n.d);
|
|
|
|
}
|
|
|
|
return errors;
|
|
|
|
}
|
|
|
|
#endif
|
2012-02-14 03:41:40 +00:00
|
|
|
|
|
|
|
R_API ut64 r_num_calc (RNum *num, const char *str) {
|
|
|
|
NumValue n;
|
|
|
|
calc_num = num;
|
|
|
|
load_token (str);
|
|
|
|
get_token ();
|
|
|
|
n = expr (0);
|
|
|
|
//if (curr_tok == END) return 0LL; // XXX: Error
|
|
|
|
//if (curr_tok == PRINT) //return 0LL; // XXX: the fuck
|
|
|
|
// n = expr (0);
|
|
|
|
#if 0
|
|
|
|
// TODO: add support for floating point valuez
|
|
|
|
if (n.d != ((double)(ut64)n.d))
|
|
|
|
eprintf ("floating value: %lf\n", n.d);
|
|
|
|
#endif
|
|
|
|
return n.n;
|
|
|
|
}
|