2021-08-13 19:13:13 +00:00
|
|
|
|
/* ported to C by pancake for r2 in 2012-2021 */
|
2012-02-14 04:26:41 +00:00
|
|
|
|
// TODO: integrate floating point support
|
|
|
|
|
// TODO: do not use global variables
|
2012-01-31 01:45:17 +00:00
|
|
|
|
/*
|
|
|
|
|
Reference Chapter 6:
|
|
|
|
|
"The C++ Programming Language", Special Edition.
|
2014-04-25 00:37:18 +00:00
|
|
|
|
Bjarne Stroustrup,Addison-Wesley Pub Co; 3 edition (February 15, 2000)
|
|
|
|
|
ISBN: 0201700735
|
2012-01-31 01:45:17 +00:00
|
|
|
|
*/
|
|
|
|
|
|
2012-08-10 09:30:27 +00:00
|
|
|
|
#include <r_types.h>
|
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>
|
|
|
|
|
|
|
|
|
|
/* accessors */
|
2012-08-10 09:30:27 +00:00
|
|
|
|
static inline RNumCalcValue Nset(ut64 v) { RNumCalcValue n; n.d = (double)v; n.n = v; return n; }
|
|
|
|
|
static inline RNumCalcValue Nsetf(double v) { RNumCalcValue n; n.d = v; n.n = (ut64)v; return n; }
|
2014-05-02 23:23:12 +00:00
|
|
|
|
//UNUSED static inline RNumCalcValue Naddf(RNumCalcValue n, double v) { n.d += v; n.n += (ut64)v; return n; }
|
2012-08-10 09:30:27 +00:00
|
|
|
|
static inline RNumCalcValue Naddi(RNumCalcValue n, ut64 v) { n.d += (double)v; n.n += v; return n; }
|
|
|
|
|
static inline RNumCalcValue Nsubi(RNumCalcValue n, ut64 v) { n.d -= (double)v; n.n -= v; return n; }
|
2014-02-26 17:31:20 +00:00
|
|
|
|
static inline RNumCalcValue Nneg(RNumCalcValue n) { n.n = ~n.n; return n; }
|
2020-12-17 21:24:27 +00:00
|
|
|
|
static inline RNumCalcValue Nor(RNumCalcValue n, RNumCalcValue v) { n.d = v.d; n.n |= v.n; return n; }
|
2014-02-26 17:31:20 +00:00
|
|
|
|
static inline RNumCalcValue Nxor(RNumCalcValue n, RNumCalcValue v) { n.d = v.d; n.n ^= v.n; return n; }
|
2021-08-13 19:13:13 +00:00
|
|
|
|
static inline RNumCalcValue Nlt(RNumCalcValue n, RNumCalcValue v) { n.d = v.d; n.n = n.n < v.n; return n; }
|
|
|
|
|
static inline RNumCalcValue Ngt(RNumCalcValue n, RNumCalcValue v) { n.d = v.d; n.n = n.n > v.n; return n; }
|
2014-02-26 17:31:20 +00:00
|
|
|
|
static inline RNumCalcValue Nand(RNumCalcValue n, RNumCalcValue v) { n.d = v.d; n.n &= v.n; return n; }
|
2012-08-10 09:30:27 +00:00
|
|
|
|
static inline RNumCalcValue Nadd(RNumCalcValue n, RNumCalcValue v) { n.d += v.d; n.n += v.n; return n; }
|
|
|
|
|
static inline RNumCalcValue Nsub(RNumCalcValue n, RNumCalcValue v) { n.d -= v.d; n.n -= v.n; return n; }
|
2016-08-04 17:45:36 +00:00
|
|
|
|
static inline RNumCalcValue Nmul(RNumCalcValue n, RNumCalcValue v) {
|
|
|
|
|
n.d *= v.d;
|
|
|
|
|
n.n *= v.n;
|
|
|
|
|
return n;
|
|
|
|
|
}
|
2017-11-09 11:57:51 +00:00
|
|
|
|
|
2016-05-10 22:28:42 +00:00
|
|
|
|
static inline RNumCalcValue Nshl(RNumCalcValue n, RNumCalcValue v) { n.d += v.d; n.n <<= v.n; return n; }
|
|
|
|
|
static inline RNumCalcValue Nshr(RNumCalcValue n, RNumCalcValue v) { n.d += v.d; n.n >>= v.n; return n; }
|
2018-04-06 19:31:03 +00:00
|
|
|
|
static inline RNumCalcValue Nrol(RNumCalcValue n, RNumCalcValue v) {
|
|
|
|
|
n.d += v.d;
|
|
|
|
|
n.n = (n.n << v.n) | (n.n >> (sizeof(n.n) * 8 - v.n));
|
|
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
static inline RNumCalcValue Nror(RNumCalcValue n, RNumCalcValue v) {
|
|
|
|
|
n.d += v.d;
|
|
|
|
|
n.n = (n.n >> v.n) | (n.n << (sizeof(n.n) * 8 - v.n));
|
|
|
|
|
return n;
|
|
|
|
|
}
|
2014-02-26 18:42:56 +00:00
|
|
|
|
static inline RNumCalcValue Nmod(RNumCalcValue n, RNumCalcValue v) {
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (v.d) {
|
|
|
|
|
n.d = (n.d - (n.d / v.d));
|
|
|
|
|
} else {
|
|
|
|
|
n.d = 0;
|
|
|
|
|
}
|
|
|
|
|
if (v.n) {
|
|
|
|
|
n.n %= v.n;
|
|
|
|
|
} else {
|
|
|
|
|
n.n = 0;
|
|
|
|
|
}
|
2014-02-26 18:42:56 +00:00
|
|
|
|
return n;
|
|
|
|
|
}
|
2017-11-09 11:57:51 +00:00
|
|
|
|
|
2012-08-10 09:30:27 +00:00
|
|
|
|
static inline RNumCalcValue Ndiv(RNumCalcValue n, RNumCalcValue v) {
|
2018-09-13 08:17:26 +00:00
|
|
|
|
if (v.d) {
|
|
|
|
|
n.d /= v.d;
|
|
|
|
|
} else {
|
|
|
|
|
n.d = 0;
|
|
|
|
|
}
|
|
|
|
|
if (v.n) {
|
|
|
|
|
n.n /= v.n;
|
|
|
|
|
} else {
|
|
|
|
|
n.n = 0;
|
|
|
|
|
}
|
2012-05-31 00:41:45 +00:00
|
|
|
|
return n;
|
|
|
|
|
}
|
2012-01-31 01:45:17 +00:00
|
|
|
|
|
2012-08-10 09:30:27 +00:00
|
|
|
|
static RNumCalcValue expr(RNum*, RNumCalc*, int);
|
|
|
|
|
static RNumCalcValue term(RNum*, RNumCalc*, int);
|
|
|
|
|
static void error(RNum*, RNumCalc*, const char *);
|
|
|
|
|
static RNumCalcValue prim(RNum*, RNumCalc*, int);
|
|
|
|
|
static RNumCalcToken get_token(RNum*, RNumCalc*);
|
2012-02-14 03:41:40 +00:00
|
|
|
|
|
2012-08-10 09:30:27 +00:00
|
|
|
|
static void error(RNum *num, RNumCalc *nc, const char *s) {
|
|
|
|
|
nc->errors++;
|
|
|
|
|
nc->calc_err = s;
|
2012-02-14 03:41:40 +00:00
|
|
|
|
//fprintf (stderr, "error: %s\n", s);
|
2012-01-31 01:45:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-08-10 09:30:27 +00:00
|
|
|
|
static RNumCalcValue expr(RNum *num, RNumCalc *nc, int get) {
|
|
|
|
|
RNumCalcValue left = term (num, nc, get);
|
2012-01-31 01:45:17 +00:00
|
|
|
|
for (;;) {
|
2014-02-26 17:31:20 +00:00
|
|
|
|
switch (nc->curr_tok) {
|
2016-05-10 22:28:42 +00:00
|
|
|
|
case RNCSHL: left = Nshl (left, term (num, nc, 1)); break;
|
|
|
|
|
case RNCSHR: left = Nshr (left, term (num, nc, 1)); break;
|
2018-04-06 19:31:03 +00:00
|
|
|
|
case RNCROL: left = Nrol (left, term (num, nc, 1)); break;
|
|
|
|
|
case RNCROR: left = Nror (left, term (num, nc, 1)); break;
|
2014-02-26 17:31:20 +00:00
|
|
|
|
case RNCPLUS: left = Nadd (left, term (num, nc, 1)); break;
|
|
|
|
|
case RNCMINUS: left = Nsub (left, term (num, nc, 1)); break;
|
|
|
|
|
case RNCXOR: left = Nxor (left, term (num, nc, 1)); break;
|
2020-12-17 21:24:27 +00:00
|
|
|
|
case RNCOR: left = Nor (left, term (num, nc, 1)); break;
|
2014-02-26 17:31:20 +00:00
|
|
|
|
case RNCAND: left = Nand (left, term (num, nc, 1)); break;
|
2021-08-13 19:13:13 +00:00
|
|
|
|
case RNCLT: left = Nlt (left, term (num, nc, 1)); break;
|
|
|
|
|
case RNCGT: left = Ngt (left, term (num, nc, 1)); break;
|
2014-02-26 17:31:20 +00:00
|
|
|
|
default:
|
|
|
|
|
return left;
|
|
|
|
|
}
|
2012-01-31 01:45:17 +00:00
|
|
|
|
}
|
2013-04-02 10:45:16 +00:00
|
|
|
|
return left;
|
2012-01-31 01:45:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-08-10 09:30:27 +00:00
|
|
|
|
static RNumCalcValue term(RNum *num, RNumCalc *nc, int get) {
|
|
|
|
|
RNumCalcValue left = prim (num, nc, get);
|
2012-01-31 01:45:17 +00:00
|
|
|
|
for (;;) {
|
2012-08-10 09:30:27 +00:00
|
|
|
|
if (nc->curr_tok == RNCMUL) {
|
|
|
|
|
left = Nmul (left, prim (num, nc, 1));
|
2017-02-01 22:20:20 +00:00
|
|
|
|
} else if (nc->curr_tok == RNCMOD) {
|
2014-02-26 18:42:56 +00:00
|
|
|
|
RNumCalcValue d = prim (num, nc, 1);
|
|
|
|
|
if (!d.d) {
|
|
|
|
|
//error (num, nc, "divide by 0");
|
|
|
|
|
return d;
|
|
|
|
|
}
|
|
|
|
|
left = Nmod (left, d);
|
2017-02-01 22:20:20 +00:00
|
|
|
|
} else if (nc->curr_tok == RNCDIV) {
|
2012-08-10 09:30:27 +00:00
|
|
|
|
RNumCalcValue d = prim (num, nc, 1);
|
2014-11-18 00:33:56 +00:00
|
|
|
|
if (num != NULL && (!d.d || !d.n)) {
|
2014-11-07 11:16:29 +00:00
|
|
|
|
num->dbz = 1;
|
2012-01-31 01:45:17 +00:00
|
|
|
|
return d;
|
|
|
|
|
}
|
|
|
|
|
left = Ndiv (left, d);
|
2017-02-01 22:20:20 +00:00
|
|
|
|
} else {
|
|
|
|
|
return left;
|
|
|
|
|
}
|
2012-01-31 01:45:17 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-10 09:30:27 +00:00
|
|
|
|
static RNumCalcValue prim(RNum *num, RNumCalc *nc, int get) {
|
|
|
|
|
RNumCalcValue v = {0};
|
2017-03-12 22:15:57 +00:00
|
|
|
|
if (get) {
|
|
|
|
|
get_token (num, nc);
|
|
|
|
|
}
|
2012-08-10 09:30:27 +00:00
|
|
|
|
switch (nc->curr_tok) {
|
|
|
|
|
case RNCNUMBER:
|
|
|
|
|
v = nc->number_value;
|
|
|
|
|
get_token (num, nc);
|
2012-01-31 01:45:17 +00:00
|
|
|
|
return v;
|
2012-08-10 09:30:27 +00:00
|
|
|
|
case RNCNAME:
|
|
|
|
|
//fprintf (stderr, "error: unknown keyword (%s)\n", nc->string_value);
|
|
|
|
|
//double& v = table[nc->string_value];
|
2018-01-08 02:22:26 +00:00
|
|
|
|
r_str_trim (nc->string_value);
|
2012-08-10 09:30:27 +00:00
|
|
|
|
v = Nset (r_num_get (num, nc->string_value));
|
|
|
|
|
get_token (num, nc);
|
2014-04-25 00:37:18 +00:00
|
|
|
|
if (nc->curr_tok == RNCASSIGN) {
|
2012-08-10 09:30:27 +00:00
|
|
|
|
v = expr (num, nc, 1);
|
2014-04-25 00:37:18 +00:00
|
|
|
|
}
|
2017-02-01 22:20:20 +00:00
|
|
|
|
if (nc->curr_tok == RNCINC) {
|
|
|
|
|
Naddi (v, 1);
|
|
|
|
|
}
|
|
|
|
|
if (nc->curr_tok == RNCDEC) {
|
|
|
|
|
Nsubi (v, 1);
|
|
|
|
|
}
|
2012-01-31 01:45:17 +00:00
|
|
|
|
return v;
|
2014-02-26 17:31:20 +00:00
|
|
|
|
case RNCNEG:
|
|
|
|
|
get_token (num, nc);
|
|
|
|
|
return Nneg (nc->number_value); //prim (num, nc, 1), 1);
|
2017-03-12 22:15:57 +00:00
|
|
|
|
case RNCINC:
|
|
|
|
|
return Naddi (prim (num, nc, 1), 1);
|
|
|
|
|
case RNCDEC:
|
|
|
|
|
return Naddi (prim (num, nc, 1), -1);
|
2020-12-17 21:24:27 +00:00
|
|
|
|
case RNCOR:
|
|
|
|
|
return Nor (v, prim (num, nc, 1));
|
2017-03-12 22:15:57 +00:00
|
|
|
|
case RNCMINUS:
|
|
|
|
|
return Nsub (v, prim (num, nc, 1));
|
2012-08-10 09:30:27 +00:00
|
|
|
|
case RNCLEFTP:
|
|
|
|
|
v = expr (num, nc, 1);
|
2014-04-25 00:37:18 +00:00
|
|
|
|
if (nc->curr_tok == RNCRIGHTP) {
|
2012-08-10 09:30:27 +00:00
|
|
|
|
get_token (num, nc);
|
2017-02-01 22:20:20 +00:00
|
|
|
|
} else {
|
|
|
|
|
error (num, nc, " ')' expected");
|
|
|
|
|
}
|
2021-08-13 19:13:13 +00:00
|
|
|
|
case RNCLT:
|
|
|
|
|
case RNCGT:
|
2012-08-10 09:30:27 +00:00
|
|
|
|
case RNCEND:
|
2014-02-26 18:42:56 +00:00
|
|
|
|
case RNCXOR:
|
|
|
|
|
case RNCAND:
|
2012-08-10 09:30:27 +00:00
|
|
|
|
case RNCPLUS:
|
2014-02-26 18:42:56 +00:00
|
|
|
|
case RNCMOD:
|
2012-08-10 09:30:27 +00:00
|
|
|
|
case RNCMUL:
|
|
|
|
|
case RNCDIV:
|
|
|
|
|
case RNCPRINT:
|
|
|
|
|
case RNCASSIGN:
|
|
|
|
|
case RNCRIGHTP:
|
2016-05-10 22:28:42 +00:00
|
|
|
|
case RNCSHL:
|
|
|
|
|
case RNCSHR:
|
2018-04-06 19:31:03 +00:00
|
|
|
|
case RNCROL:
|
|
|
|
|
case RNCROR:
|
2012-02-15 22:42:27 +00:00
|
|
|
|
return v;
|
2012-08-10 09:30:27 +00:00
|
|
|
|
//default: error (num, nc, "primary expected");
|
2012-01-31 01:45:17 +00:00
|
|
|
|
}
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-10 09:30:27 +00:00
|
|
|
|
static void cin_putback (RNum *num, RNumCalc *nc, char c) {
|
|
|
|
|
nc->oc = c;
|
2012-01-31 01:45:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-02-01 22:15:32 +00:00
|
|
|
|
R_API const char *r_num_calc_index(RNum *num, const char *p) {
|
|
|
|
|
if (!num) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2012-06-27 23:27:40 +00:00
|
|
|
|
if (p) {
|
2012-08-10 09:30:27 +00:00
|
|
|
|
num->nc.calc_buf = p;
|
2012-12-20 10:31:38 +00:00
|
|
|
|
num->nc.calc_len = strlen (p);
|
2012-08-10 09:30:27 +00:00
|
|
|
|
num->nc.calc_i = 0;
|
2012-06-27 23:27:40 +00:00
|
|
|
|
}
|
2012-08-10 09:30:27 +00:00
|
|
|
|
return num->nc.calc_buf + num->nc.calc_i;
|
2012-06-27 23:27:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-08-10 09:30:27 +00:00
|
|
|
|
static int cin_get(RNum *num, RNumCalc *nc, char *c) {
|
|
|
|
|
if (nc->oc) {
|
|
|
|
|
*c = nc->oc;
|
|
|
|
|
nc->oc = 0;
|
2012-01-31 01:45:17 +00:00
|
|
|
|
} else {
|
2019-02-10 02:00:21 +00:00
|
|
|
|
if (!nc->calc_buf || !*nc->calc_buf) {
|
2012-01-31 01:45:17 +00:00
|
|
|
|
return 0;
|
2017-02-01 22:20:20 +00:00
|
|
|
|
}
|
2012-08-10 09:30:27 +00:00
|
|
|
|
*c = nc->calc_buf[nc->calc_i];
|
2017-02-01 22:20:20 +00:00
|
|
|
|
if (*c) {
|
|
|
|
|
nc->calc_i++;
|
|
|
|
|
} else {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2012-01-31 01:45:17 +00:00
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-10 09:30:27 +00:00
|
|
|
|
static int cin_get_num(RNum *num, RNumCalc *nc, RNumCalcValue *n) {
|
2012-01-31 01:45:17 +00:00
|
|
|
|
double d;
|
2018-09-14 14:58:37 +00:00
|
|
|
|
char str[R_NUMCALC_STRSZ + 1]; // TODO: move into the heap?
|
2012-01-31 01:45:17 +00:00
|
|
|
|
int i = 0;
|
|
|
|
|
char c;
|
|
|
|
|
str[0] = 0;
|
2012-08-10 09:30:27 +00:00
|
|
|
|
while (cin_get (num, nc, &c)) {
|
2020-12-16 13:49:50 +00:00
|
|
|
|
if (c != '_' && c != ':' && c != '.' && !isalnum ((ut8)c)) {
|
2012-08-10 09:30:27 +00:00
|
|
|
|
cin_putback (num, nc, c);
|
2012-01-31 01:45:17 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2015-11-11 23:20:37 +00:00
|
|
|
|
if (i < R_NUMCALC_STRSZ) {
|
2012-01-31 01:45:17 +00:00
|
|
|
|
str[i++] = c;
|
2014-04-25 00:37:18 +00:00
|
|
|
|
}
|
2012-01-31 01:45:17 +00:00
|
|
|
|
}
|
|
|
|
|
str[i] = 0;
|
2012-08-10 09:30:27 +00:00
|
|
|
|
*n = Nset (r_num_get (num, str));
|
2017-03-12 22:15:57 +00:00
|
|
|
|
if (IS_DIGIT (*str) && strchr (str, '.')) {
|
2017-02-01 22:20:20 +00:00
|
|
|
|
if (sscanf (str, "%lf", &d) < 1) {
|
2012-02-14 04:26:41 +00:00
|
|
|
|
return 0;
|
2017-02-01 22:20:20 +00:00
|
|
|
|
}
|
2017-03-12 22:15:57 +00:00
|
|
|
|
if (n->n < d) {
|
|
|
|
|
*n = Nsetf (d);
|
|
|
|
|
}
|
|
|
|
|
n->d = d;
|
2012-02-14 04:26:41 +00:00
|
|
|
|
}
|
2012-01-31 01:45:17 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-10 09:30:27 +00:00
|
|
|
|
static RNumCalcToken get_token(RNum *num, RNumCalc *nc) {
|
2013-01-04 13:51:21 +00:00
|
|
|
|
char ch = 0, c = 0;
|
2012-01-31 01:45:17 +00:00
|
|
|
|
|
2017-07-10 10:31:50 +00:00
|
|
|
|
do {
|
|
|
|
|
if (!cin_get (num, nc, &ch)) {
|
|
|
|
|
return nc->curr_tok = RNCEND;
|
|
|
|
|
}
|
|
|
|
|
} while (ch != '\n' && isspace ((ut8)ch));
|
2012-01-31 01:45:17 +00:00
|
|
|
|
|
|
|
|
|
switch (ch) {
|
2012-06-27 23:27:40 +00:00
|
|
|
|
case 0:
|
2012-01-31 01:45:17 +00:00
|
|
|
|
case ';':
|
|
|
|
|
case '\n':
|
2012-08-10 09:30:27 +00:00
|
|
|
|
return nc->curr_tok = RNCEND;
|
2012-01-31 01:45:17 +00:00
|
|
|
|
case '+': // added for ++name and name++
|
2017-02-01 22:20:20 +00:00
|
|
|
|
if (cin_get (num, nc, &c) && c == '+') {
|
2012-08-10 09:30:27 +00:00
|
|
|
|
return nc->curr_tok = RNCINC;
|
2017-02-01 22:20:20 +00:00
|
|
|
|
}
|
2012-08-10 09:30:27 +00:00
|
|
|
|
cin_putback (num, nc, c);
|
|
|
|
|
return nc->curr_tok = (RNumCalcToken) ch;
|
2014-02-26 17:31:20 +00:00
|
|
|
|
// negate hack
|
|
|
|
|
case '~':
|
2017-02-01 22:20:20 +00:00
|
|
|
|
if (cin_get (num, nc, &c) && c == '-') {
|
2014-02-26 17:31:20 +00:00
|
|
|
|
return nc->curr_tok = RNCNEG;
|
2017-02-01 22:20:20 +00:00
|
|
|
|
}
|
2014-02-26 17:31:20 +00:00
|
|
|
|
cin_putback (num, nc, c);
|
|
|
|
|
return nc->curr_tok = (RNumCalcToken) ch;
|
|
|
|
|
// negative number
|
2012-01-31 01:45:17 +00:00
|
|
|
|
case '-':
|
2017-02-01 22:20:20 +00:00
|
|
|
|
if (cin_get (num, nc, &c) && c == '-') {
|
2012-08-10 09:30:27 +00:00
|
|
|
|
return nc->curr_tok = RNCDEC;
|
2017-02-01 22:20:20 +00:00
|
|
|
|
}
|
2012-08-10 09:30:27 +00:00
|
|
|
|
cin_putback (num, nc, c);
|
|
|
|
|
return nc->curr_tok = (RNumCalcToken) ch;
|
2018-04-06 19:31:03 +00:00
|
|
|
|
case '<':
|
2021-08-13 19:13:13 +00:00
|
|
|
|
if (cin_get (num, nc, &c) && c == '<') { // "<<" = shift left
|
|
|
|
|
if (cin_get (num, nc, &c) && c == '<') { // "<<<" = rotate left
|
2018-04-06 19:31:03 +00:00
|
|
|
|
return nc->curr_tok = RNCROL;
|
|
|
|
|
}
|
|
|
|
|
cin_putback (num, nc, c);
|
|
|
|
|
return nc->curr_tok = RNCSHL;
|
|
|
|
|
}
|
|
|
|
|
cin_putback (num, nc, c);
|
2021-08-13 19:13:13 +00:00
|
|
|
|
return nc->curr_tok = RNCLT; // RNCEND;
|
2018-04-06 19:31:03 +00:00
|
|
|
|
case '>':
|
|
|
|
|
if (cin_get (num, nc, &c) && c == '>') {
|
|
|
|
|
if (cin_get (num, nc, &c) && c == '>') {
|
|
|
|
|
return nc->curr_tok = RNCROR;
|
|
|
|
|
}
|
|
|
|
|
cin_putback (num, nc, c);
|
|
|
|
|
return nc->curr_tok = RNCSHR;
|
|
|
|
|
}
|
|
|
|
|
cin_putback (num, nc, c);
|
2021-08-13 19:13:13 +00:00
|
|
|
|
return nc->curr_tok = RNCGT; // RNCEND
|
2014-02-26 17:31:20 +00:00
|
|
|
|
case '^':
|
|
|
|
|
case '&':
|
|
|
|
|
case '|':
|
2012-01-31 01:45:17 +00:00
|
|
|
|
case '*':
|
2014-02-26 18:42:56 +00:00
|
|
|
|
case '%':
|
2012-01-31 01:45:17 +00:00
|
|
|
|
case '/':
|
|
|
|
|
case '(':
|
|
|
|
|
case ')':
|
|
|
|
|
case '=':
|
2012-08-10 09:30:27 +00:00
|
|
|
|
return nc->curr_tok = (RNumCalcToken) ch;
|
2014-02-26 17:31:20 +00:00
|
|
|
|
case '0': case '1': case '2': case '3': case '4':
|
2012-01-31 01:45:17 +00:00
|
|
|
|
case '5': case '6': case '7': case '8': case '9':
|
|
|
|
|
case '.':
|
2012-08-10 09:30:27 +00:00
|
|
|
|
cin_putback (num, nc, ch);
|
|
|
|
|
if (!cin_get_num (num, nc, &nc->number_value)) {
|
|
|
|
|
error (num, nc, "invalid number conversion");
|
2012-01-31 01:45:17 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
2012-08-10 09:30:27 +00:00
|
|
|
|
return nc->curr_tok = RNCNUMBER;
|
2014-04-25 00:37:18 +00:00
|
|
|
|
|
2012-02-15 10:11:25 +00:00
|
|
|
|
#define isvalidchar(x) \
|
2018-08-30 11:16:50 +00:00
|
|
|
|
(isalnum(x) || (x)==':' || (x)=='$' || (x)=='.' || (x)=='_' || (x)=='?' || (x)=='\\' \
|
2021-08-13 18:29:17 +00:00
|
|
|
|
|| (x)==' ' || (x)=='[' || (x)==']' || (x)=='}' || (x)=='{' || ((x)>='0' && (x)<='9'))
|
2014-04-25 00:37:18 +00:00
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
{
|
2012-01-31 01:45:17 +00:00
|
|
|
|
int i = 0;
|
2016-06-14 00:19:20 +00:00
|
|
|
|
#define stringValueAppend(x) { \
|
2016-06-14 01:14:48 +00:00
|
|
|
|
const size_t max = sizeof (nc->string_value) - 1; \
|
|
|
|
|
if (i < max) nc->string_value[i++] = x; \
|
|
|
|
|
else nc->string_value[max] = 0; \
|
2016-06-14 00:19:20 +00:00
|
|
|
|
}
|
|
|
|
|
stringValueAppend(ch);
|
2012-06-27 23:27:40 +00:00
|
|
|
|
if (ch == '[') {
|
2012-08-10 09:30:27 +00:00
|
|
|
|
while (cin_get (num, nc, &ch) && ch!=']') {
|
2015-07-08 20:52:06 +00:00
|
|
|
|
if (i > R_NUMCALC_STRSZ - 1) {
|
2012-08-10 09:30:27 +00:00
|
|
|
|
error (num, nc, "string too long");
|
2012-06-27 23:27:40 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2016-06-14 00:19:20 +00:00
|
|
|
|
stringValueAppend(ch);
|
2012-01-31 01:45:17 +00:00
|
|
|
|
}
|
2016-06-14 00:19:20 +00:00
|
|
|
|
stringValueAppend(ch);
|
2012-06-27 23:27:40 +00:00
|
|
|
|
} else {
|
2014-12-04 03:12:01 +00:00
|
|
|
|
while (cin_get (num, nc, &ch) && isvalidchar ((unsigned char)ch)) {
|
2017-02-01 22:20:20 +00:00
|
|
|
|
if (i >= R_NUMCALC_STRSZ) {
|
2012-08-10 09:30:27 +00:00
|
|
|
|
error (num, nc, "string too long");
|
2012-06-27 23:27:40 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2016-06-14 00:19:20 +00:00
|
|
|
|
stringValueAppend(ch);
|
2012-06-27 23:27:40 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-08-13 18:29:17 +00:00
|
|
|
|
stringValueAppend (0);
|
|
|
|
|
if (ch != '\'') {
|
2015-11-11 23:20:37 +00:00
|
|
|
|
cin_putback (num, nc, ch);
|
2016-06-14 00:19:20 +00:00
|
|
|
|
}
|
2012-08-10 09:30:27 +00:00
|
|
|
|
return nc->curr_tok = RNCNAME;
|
2014-02-26 17:31:20 +00:00
|
|
|
|
}
|
2012-01-31 01:45:17 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-10 09:30:27 +00:00
|
|
|
|
static void load_token(RNum *num, RNumCalc *nc, const char *s) {
|
|
|
|
|
nc->calc_i = 0;
|
2017-02-01 22:15:32 +00:00
|
|
|
|
nc->calc_len = strlen (s);
|
2012-08-10 09:30:27 +00:00
|
|
|
|
nc->calc_buf = s;
|
|
|
|
|
nc->calc_err = NULL;
|
2012-02-14 03:41:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-05-23 20:07:32 +00:00
|
|
|
|
R_API ut64 r_num_calc(RNum *num, const char *str, const char **err) {
|
2012-08-10 09:30:27 +00:00
|
|
|
|
RNumCalcValue n;
|
|
|
|
|
RNumCalc *nc, nc_local;
|
2017-02-01 22:20:20 +00:00
|
|
|
|
if (!str || !*str) {
|
2012-02-14 04:26:41 +00:00
|
|
|
|
return 0LL;
|
2017-02-01 22:20:20 +00:00
|
|
|
|
}
|
2014-11-07 11:16:29 +00:00
|
|
|
|
if (num) {
|
|
|
|
|
nc = &num->nc;
|
|
|
|
|
num->dbz = 0;
|
|
|
|
|
} else {
|
2012-08-10 09:30:27 +00:00
|
|
|
|
nc = &nc_local;
|
2014-11-07 11:16:29 +00:00
|
|
|
|
}
|
2012-08-10 09:30:27 +00:00
|
|
|
|
/* init */
|
|
|
|
|
nc->curr_tok = RNCPRINT;
|
|
|
|
|
nc->number_value.d = 0.0;
|
|
|
|
|
nc->number_value.n = 0LL;
|
|
|
|
|
nc->errors = 0;
|
|
|
|
|
nc->oc = 0;
|
|
|
|
|
nc->calc_err = NULL;
|
|
|
|
|
nc->calc_i = 0;
|
2012-12-20 10:31:38 +00:00
|
|
|
|
nc->calc_len = 0;
|
2012-08-10 09:30:27 +00:00
|
|
|
|
nc->calc_buf = NULL;
|
2018-04-20 23:21:55 +00:00
|
|
|
|
nc->under_calc = true;
|
2012-08-10 09:30:27 +00:00
|
|
|
|
|
|
|
|
|
load_token (num, nc, str);
|
|
|
|
|
get_token (num, nc);
|
|
|
|
|
n = expr (num, nc, 0);
|
2017-02-01 22:20:20 +00:00
|
|
|
|
if (err) {
|
|
|
|
|
*err = nc->calc_err;
|
|
|
|
|
}
|
2016-08-04 17:45:36 +00:00
|
|
|
|
if (num) {
|
|
|
|
|
num->fvalue = n.d;
|
|
|
|
|
}
|
2018-04-20 23:21:55 +00:00
|
|
|
|
nc->under_calc = false;
|
2012-02-14 03:41:40 +00:00
|
|
|
|
return n.n;
|
|
|
|
|
}
|
2012-06-27 23:27:40 +00:00
|
|
|
|
|
|
|
|
|
#ifdef TEST
|
|
|
|
|
int main(int argc, char* argv[]) {
|
2012-08-10 09:30:27 +00:00
|
|
|
|
RNumCalcValue n;
|
|
|
|
|
RNumCalc nc;
|
2012-06-27 23:27:40 +00:00
|
|
|
|
while (!feof (stdin)) {
|
2012-08-10 09:30:27 +00:00
|
|
|
|
get_token (nc);
|
2017-02-01 22:20:20 +00:00
|
|
|
|
if (nc.curr_tok == RNCEND) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (nc.curr_tok == RNCPRINT) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2012-08-10 09:30:27 +00:00
|
|
|
|
n = expr (num, nc, 0);
|
2017-02-01 22:20:20 +00:00
|
|
|
|
if (n.d == ((double)(int)n.d)) {
|
2012-06-27 23:27:40 +00:00
|
|
|
|
printf ("%llx\n", n.n);
|
2017-02-01 22:20:20 +00:00
|
|
|
|
} else {
|
|
|
|
|
printf ("%lf\n", n.d);
|
|
|
|
|
}
|
2012-06-27 23:27:40 +00:00
|
|
|
|
}
|
2012-08-10 09:30:27 +00:00
|
|
|
|
return nc->errors;
|
2012-06-27 23:27:40 +00:00
|
|
|
|
}
|
|
|
|
|
#endif
|